home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pmos2002.zip / SRC / SOUNDEFF.MOD < prev    next >
Text File  |  1996-10-25  |  7KB  |  229 lines

  1. IMPLEMENTATION MODULE SoundEffects;
  2.  
  3.         (********************************************************)
  4.         (*                                                      *)
  5.         (*      Procedures to produce audible output.           *)
  6.         (*                                                      *)
  7.         (*      Programmer:     P. Moylan                       *)
  8.         (*      Last edited:    25 October 1996                 *)
  9.         (*      Status:         Seems to be working             *)
  10.         (*                                                      *)
  11.         (********************************************************)
  12.  
  13. FROM Trace IMPORT
  14.     (* proc *)  TraceOn, InTrace, OutTrace;
  15.  
  16. FROM SYSTEM IMPORT
  17.     (* proc *)  ADR;
  18.  
  19. FROM Storage IMPORT
  20.     (* proc *)  ALLOCATE, DEALLOCATE;
  21.  
  22. FROM Queues IMPORT
  23.     (* type *)  Queue,
  24.     (* proc *)  CreateQueue, AddToQueue, TakeFromQueue, Empty;
  25.  
  26. FROM Timer IMPORT
  27.     (* proc *)  Sleep;
  28.  
  29. FROM Semaphores IMPORT
  30.     (* type *)  Semaphore,
  31.     (* proc *)  CreateSemaphore, Wait, Signal;
  32.  
  33. FROM TaskControl IMPORT
  34.     (* proc *)  CreateTask;
  35.  
  36. FROM OS2 IMPORT
  37.     (* proc *)  DosBeep;
  38.  
  39. (************************************************************************)
  40.  
  41. CONST
  42.     OffCode = 0CH;  OnCode = 0FH;
  43.  
  44. TYPE
  45.  
  46.     <* m2extensions+ *>
  47.     NoteArrayPointer = POINTER TO ARRAY [0..1000] OF Note;
  48.     <* m2extensions- *>
  49.  
  50.     SemaphorePointer = POINTER TO Semaphore;
  51.  
  52.     QueuePointer = POINTER TO QueueElement;
  53.  
  54.     (* The music waiting to be played is ordered by having a queue of   *)
  55.     (* waiting entries.  Each element of the queue is a record with a   *)
  56.     (* pointer to an array of music data, the last subscript of that    *)
  57.     (* array (the first subscript is always assumed to be zero), and a  *)
  58.     (* pointer to the semaphore on which we will perform a Signal to    *)
  59.     (* indicate that we have finished working on this section of data.  *)
  60.     (* Notice that the queue is not directly a queue of data.  Rather,  *)
  61.     (* it is a queue of pointers to data.                               *)
  62.  
  63.     QueueElement =  RECORD
  64.                         dataptr: NoteArrayPointer;
  65.                         lastsubscript: CARDINAL;
  66.                         CompletionSemaphoreAddress: SemaphorePointer;
  67.                     END (*RECORD*);
  68.  
  69. (************************************************************************)
  70.  
  71. VAR
  72.  
  73.     (* PlayQueue is the actual queue.   *)
  74.  
  75.     PlayQueue: Queue;
  76.  
  77.     (* beep holds the data to be used to produce a "beep" noise.        *)
  78.  
  79.     beep: ARRAY [0..1] OF Note;
  80.  
  81.     (* The completion semaphore used when doing the beep.       *)
  82.  
  83.     BeepSem: Semaphore;
  84.  
  85. (************************************************************************)
  86.  
  87. PROCEDURE Play (VAR (*IN*) playdata: ARRAY OF Note;
  88.                         VAR (*INOUT*) done: Semaphore);
  89.  
  90.     (* Adds the array to the list of music queued up waiting to be      *)
  91.     (* played.  The actual playing is handled by a separate task - see  *)
  92.     (* PlayerTask later in this module.  On return from this procedure, *)
  93.     (* the playing is not necessarily over.  The caller must perform a  *)
  94.     (* Wait(done) to know when the array playdata is no longer in use.  *)
  95.  
  96.     VAR elementpointer: QueuePointer;
  97.  
  98.     BEGIN
  99.         InTrace ("Play");
  100.         NEW (elementpointer);
  101.         WITH elementpointer^ DO
  102.             dataptr := ADR (playdata);  lastsubscript := HIGH (playdata);
  103.             CompletionSemaphoreAddress := ADR(done);
  104.         END (*WITH*);
  105.         AddToQueue (PlayQueue, elementpointer);
  106.         OutTrace ("Play");
  107.     END Play;
  108.  
  109. (************************************************************************)
  110.  
  111. PROCEDURE Beep;
  112.  
  113.     (* Produces a short "beep" noise.   *)
  114.  
  115.     BEGIN
  116.         InTrace ("Beep");
  117.         Wait (BeepSem);
  118.         Play (beep, BeepSem);
  119.         OutTrace ("Beep");
  120.     END Beep;
  121.  
  122. (************************************************************************)
  123.  
  124. PROCEDURE PlayerTask;
  125.  
  126.     (* This is the procedure which does all the real work.  It runs as  *)
  127.     (* a separate task, which typically spends most of its time         *)
  128.     (* blocked while waiting for something to play.                     *)
  129.  
  130.     (* A duration code of 0 indicates the end of the data, in cases     *)
  131.     (* where the data do not fill the entire array.                     *)
  132.     (* A period code of 1, with a nonzero duration, indicates a rest.   *)
  133.  
  134.     CONST FreqScale = 1193000;
  135.  
  136.     VAR arrayptr: NoteArrayPointer;  j, top, Period, Duration: CARDINAL;
  137.         doneaddress: SemaphorePointer;  qptr: QueuePointer;
  138.  
  139.     BEGIN
  140.         (*TraceOn (11, 24, 40, 79, 1);*)
  141.         LOOP    (* forever *)
  142.  
  143.             (* Note that this task will remain blocked inside procedure *)
  144.             (* TakeFromQueue while there is nothing to play.            *)
  145.  
  146.             qptr := TakeFromQueue (PlayQueue);
  147.             WITH qptr^ DO
  148.                 arrayptr := dataptr;
  149.                 top := lastsubscript;
  150.                 doneaddress := CompletionSemaphoreAddress;
  151.             END (*WITH*);
  152.             DISPOSE (qptr);
  153.  
  154.             j := 0;
  155.             LOOP
  156.                 Period := arrayptr^[j].period;
  157.                 Duration := arrayptr^[j].duration;
  158.  
  159.                 (* A duration code of 0 indicates the end of the data.  *)
  160.  
  161.                 IF Duration = 0 THEN
  162.                     EXIT(*LOOP*);
  163.                 END (*IF*);
  164.  
  165.                 IF Period <= 1 THEN
  166.                     (* Rest *)
  167.                     Sleep (Duration);
  168.                 ELSE
  169.                     (* We have a normal note to play. *)
  170.                     DosBeep (FreqScale DIV Period, Duration);
  171.                 END (*IF*);
  172.                 IF j = top THEN EXIT(*LOOP*) END(*IF*);
  173.                 INC (j);
  174.  
  175.             END (*LOOP*);
  176.  
  177.             (* Tell the user task that we have finished with this       *)
  178.             (* buffer-full of data.                                     *)
  179.  
  180.             Signal (doneaddress^);
  181.  
  182.         END (*LOOP*);
  183.     END PlayerTask;
  184.  
  185. (************************************************************************)
  186. (*                      MODULE TERMINATION                              *)
  187. (************************************************************************)
  188.  
  189. PROCEDURE CloseDown;
  190.  
  191.     (* Brings the module to an orderly halt.    *)
  192.  
  193.     VAR qptr: QueuePointer;
  194.  
  195.     BEGIN
  196.         WHILE NOT Empty(PlayQueue) DO
  197.             qptr := TakeFromQueue (PlayQueue);
  198.             Signal (qptr^.CompletionSemaphoreAddress^);
  199.             DISPOSE (qptr);
  200.         END (*WHILE*);
  201.     END CloseDown;
  202.  
  203. (************************************************************************)
  204. (*                      MODULE INITIALISATION                           *)
  205. (************************************************************************)
  206.  
  207. BEGIN
  208.  
  209.     (* Create an initially empty queue of music to be played.   *)
  210.  
  211.     CreateQueue (PlayQueue);
  212.  
  213.     (* Define the parameters of a "beep" noise. *)
  214.  
  215.     beep[0].period := 1000;
  216.     beep[0].duration := 40;
  217.     beep[1].period := 1;
  218.     beep[1].duration := 20;
  219.     CreateSemaphore (BeepSem, 1);
  220.  
  221.     (* Create the task which plays the music.   *)
  222.  
  223.     CreateTask (PlayerTask, 10, "Sound effects");
  224.  
  225. FINALLY
  226.     CloseDown;
  227. END SoundEffects.
  228.  
  229.