home *** CD-ROM | disk | FTP | other *** search
/ World of Sound / World of Sound.iso / utils / misc / fmsynth / src / source.lha / AudioSupport.mod < prev    next >
Encoding:
Text File  |  1993-06-27  |  8.0 KB  |  306 lines

  1. (*-------------------------------------------------------------------------
  2.  :Program.      AudioSupport.mod
  3.  :Contents.     Easy sound programming
  4.  :Author.       Christian Stiens
  5.  :Address.      Heustiege 2, W-4710 Lüdinghausen
  6.  :Copyright.    public domain
  7.  :Language.     Oberon
  8.  :Translator.   Amiga Oberon v2.42d
  9.  :History.      V1.0, 25-Aug-90: First release
  10.  :History.      V1.1, 24-Jul-91: Oberon, PlayLoopSound, DontAbort, SetPriority
  11.  :History.      V1.2, 24-Sep-92: Bug Fixes, CheckFilter
  12. -------------------------------------------------------------------------*)
  13.  
  14.  
  15. MODULE AudioSupport;
  16.  
  17.   (* $NilChk- $RangeChk- $OvflChk- $ClearVars- *)
  18.  
  19.   IMPORT
  20.     au : Audio,
  21.     e  : Exec,
  22.     es : ExecSupport,
  23.     hw : Hardware,
  24.     rq : Requests,
  25.     sys: SYSTEM;
  26.  
  27.  
  28.   TYPE
  29.     AudioBlock = ARRAY 3 OF au.IOAudio;
  30.  
  31.   CONST
  32.     clock  * = 3563220;  (* period = clock / sampling frequency *)
  33.  
  34.     left0  * = 0;
  35.     right0 * = 1;
  36.     right1 * = 2;
  37.     left1  * = 3;
  38.  
  39.  
  40.     cantOpen = "Can't open audio channel";
  41.     notOpen  = "Audio channel not open";
  42.     illegal  = "Illegal audio channel";
  43.  
  44.   VAR
  45.     mp0            : ARRAY 4 OF e.MsgPortPtr;
  46.     ioa0,ioa1,ioa2 : ARRAY 4 OF au.IOAudioPtr;
  47.     open           : ARRAY 4 OF BOOLEAN;
  48.     looped         : ARRAY 4 OF BOOLEAN;
  49.     lastPer,lastVol: ARRAY 4 OF INTEGER;
  50.     priority       : SHORTINT;
  51.     abort          : BOOLEAN;
  52.  
  53.  
  54. (* OpenChannel will open channels with priority pri *)
  55.  
  56.   PROCEDURE SetPriority*(pri: SHORTINT);
  57.   BEGIN
  58.     priority := pri
  59.   END SetPriority;
  60.  
  61.  
  62. (* Program will not be aborted if channels are not free *)
  63.  
  64.   PROCEDURE DontAbort*;
  65.   BEGIN
  66.     abort := FALSE;
  67.   END DontAbort;
  68.  
  69.  
  70. (* Open one channel of mask and return its channel number *)
  71.  
  72.   PROCEDURE OpenChannel*(mask: SET): SHORTINT;
  73.     VAR
  74.       allocMask : ARRAY 4 OF SHORTSET;
  75.       chan      : SHORTINT;
  76.       i         : INTEGER;
  77.       mp        : e.MsgPortPtr;
  78.       ioa       : UNTRACED POINTER TO AudioBlock;
  79.   BEGIN
  80.     IF mask * {0..3} = {} THEN mask := {0..3} END;
  81.     mp := es.CreatePort("",0);
  82.     IF mp # NIL THEN
  83.       ioa := e.AllocMem(SIZE(AudioBlock),LONGSET{e.memClear,e.public});
  84.       IF ioa # NIL THEN
  85.         ioa^[0].request.message.node.type := e.unknown;
  86.         ioa^[0].request.message.length := SIZE(au.IOAudio);
  87.         ioa^[0].request.message.replyPort := mp;
  88.         i := 0;
  89.         chan := 0; WHILE chan < 4 DO
  90.           IF chan IN mask THEN allocMask[i] := SHORTSET{chan}; INC(i) END;
  91.           INC(chan)
  92.         END;
  93.         ioa^[0].request.message.node.pri := priority;
  94.         ioa^[0].data   := sys.ADR(allocMask);
  95.         ioa^[0].length := i;
  96.         ioa^[0].request.command := au.allocate;
  97.         ioa^[0].request.flags := SHORTSET{au.noWait};
  98.         IF e.OpenDevice(au.audioName,0,sys.ADR(ioa^[0]),LONGSET{})=0 THEN
  99.           ioa^[1] := ioa^[0];
  100.           ioa^[2] := ioa^[0];
  101.           CASE sys.VAL(LONGINT,ioa[0].request.unit) OF
  102.             1: chan := left0  |
  103.             2: chan := right0 |
  104.             4: chan := right1 |
  105.             8: chan := left1
  106.           END;
  107.           mp0[chan] := mp;
  108.           ioa0[chan] := sys.ADR(ioa[0]);
  109.           ioa1[chan] := sys.ADR(ioa[1]);
  110.           ioa2[chan] := sys.ADR(ioa[2]);
  111.           ioa0[chan].data := 0;
  112.           open[chan] := TRUE;
  113.           looped[chan] := FALSE;
  114.           RETURN chan
  115.         END;
  116.         e.FreeMem(ioa,SIZE(AudioBlock));
  117.       END;
  118.       es.DeletePort(mp)
  119.     END;
  120.     rq.Assert(~abort,cantOpen);
  121.     RETURN -1
  122.   END OpenChannel;
  123.  
  124.  
  125. (* Close the channel chan (which not has to be open). All open
  126.    channels are closed automatic at program end *)
  127.  
  128.   PROCEDURE CloseChannel*(chan: SHORTINT);
  129.   BEGIN
  130.     IF (chan >= 0) & (chan <= 3) & open[chan] THEN
  131.       e.CloseDevice(ioa0[chan]);
  132.       e.FreeMem(ioa0[chan],SIZE(AudioBlock));
  133.       es.DeletePort(mp0[chan]);
  134.       open[chan] := FALSE;
  135.     END
  136.   END CloseChannel;
  137.  
  138.  
  139. (* $StackChk- *)
  140.  
  141.   PROCEDURE CheckChannel(chan: SHORTINT): BOOLEAN;
  142.   BEGIN
  143.     CASE chan OF
  144.        -1 : rq.Assert(~abort,notOpen); RETURN FALSE |
  145.      0..3 : IF open[chan] THEN RETURN TRUE
  146.             ELSE rq.Assert(~abort,notOpen); RETURN FALSE END
  147.     ELSE    rq.Assert(FALSE,illegal);
  148.     END;
  149.   END CheckChannel;
  150.  
  151.  
  152. (* Play the sample at address 'sound' (in chip mem) with period 'per'
  153.    (per >= 124), volume 'vol' (0 <= vol <= 64) 'cyc' times (cyc=0 means
  154.    forever) *)
  155.  
  156.   PROCEDURE PlaySound*(chan:SHORTINT; sound:e.APTR; size:LONGINT;
  157.                        per,vol,cyc:INTEGER);
  158.   BEGIN
  159.     IF ~CheckChannel(chan) THEN RETURN END;
  160.     IF looped[chan] THEN
  161.       e.AbortIO(ioa1[chan]);
  162.       IF e.GetMsg(mp0[chan])=NIL THEN END;
  163.     END;
  164.     e.AbortIO(ioa0[chan]);
  165.     IF e.GetMsg(mp0[chan])=NIL THEN END;
  166.     ioa0[chan].request.command := e.write;
  167.     ioa0[chan].request.flags := SHORTSET{au.pervol};
  168.     ioa0[chan].data   := sound;
  169.     ioa0[chan].length := size;
  170.     ioa0[chan].period := per;
  171.     ioa0[chan].volume := vol;
  172.     ioa0[chan].cycles := cyc;
  173.     es.BeginIO(ioa0[chan]);
  174.     lastPer[chan] := per;
  175.     lastVol[chan] := vol;
  176.     looped[chan] := FALSE;
  177.   END PlaySound;
  178.  
  179.  
  180. (* Play a looped sound with attack length 'oneShot' and looped
  181.    length 'repeat' *)
  182.  
  183.   PROCEDURE PlayLoopSound*(chan:SHORTINT; sound:e.APTR;
  184.                            oneShot,repeat:LONGINT;
  185.                            per,vol:INTEGER);
  186.   BEGIN
  187.     IF oneShot = 0 THEN
  188.       PlaySound(chan,sound,repeat,per,vol,0);
  189.       RETURN;
  190.     END;
  191.     IF repeat = 0 THEN
  192.       PlaySound(chan,sound,oneShot,per,vol,1);
  193.       RETURN;
  194.     END;
  195.     IF ~CheckChannel(chan) THEN RETURN END;
  196.     IF looped[chan] THEN
  197.       e.AbortIO(ioa1[chan]);
  198.       IF e.GetMsg(mp0[chan])=NIL THEN END;
  199.     END;
  200.     e.AbortIO(ioa0[chan]);
  201.     IF e.GetMsg(mp0[chan])=NIL THEN END;
  202.     ioa0[chan].request.command := e.write;
  203.     ioa0[chan].request.flags := SHORTSET{au.pervol};
  204.     ioa0[chan].data := sound;
  205.     ioa0[chan].length := oneShot;
  206.     ioa0[chan].period := per;
  207.     ioa0[chan].volume := vol;
  208.     ioa0[chan].cycles := 1;
  209.     es.BeginIO(ioa0[chan]);
  210.     ioa1[chan].request.command := e.write;
  211.     ioa1[chan].request.flags := SHORTSET{};
  212.     ioa1[chan].data := sys.VAL(LONGINT,sound)+oneShot;
  213.     ioa1[chan].length := repeat;
  214.     ioa1[chan].cycles := 0;
  215.     es.BeginIO(ioa1[chan]);
  216.     lastPer[chan] := per;
  217.     lastVol[chan] := vol;
  218.     looped[chan] := TRUE;
  219.   END PlayLoopSound;
  220.  
  221.  
  222. (* Stop the sound of channel 'chan' *)
  223.  
  224.   PROCEDURE StopSound*(chan: SHORTINT);
  225.   BEGIN
  226.     IF ~CheckChannel(chan) THEN RETURN END;
  227.     IF looped[chan] THEN
  228.       e.AbortIO(ioa1[chan]);
  229.       looped[chan] := FALSE;
  230.     END;
  231.     e.AbortIO(ioa0[chan]);
  232.   END StopSound;
  233.  
  234.  
  235. (* Returns 'TRUE' if channel 'chan' is playing at this moment *)
  236.  
  237.   PROCEDURE CheckSound*(chan: SHORTINT): BOOLEAN;
  238.   BEGIN
  239.     IF ~CheckChannel(chan) THEN RETURN FALSE END;
  240.     RETURN looped[chan] OR ((ioa0[chan].data#0)&(e.CheckIO(ioa0[chan])=NIL))
  241.   END CheckSound;
  242.  
  243.  
  244. (* Modifies frequency and volume of a running sound *)
  245.  
  246.   PROCEDURE ModifySound*(chan:SHORTINT; per,vol: INTEGER);
  247.   BEGIN
  248.     IF ~CheckChannel(chan) THEN RETURN END;
  249.     IF (vol#lastVol[chan]) OR (per#lastPer[chan]) THEN
  250.       ioa2[chan].request.command := au.perVol;
  251.       ioa2[chan].period := per;
  252.       ioa2[chan].volume := vol;
  253.       e.OldDoIO(ioa2[chan]);
  254.       lastPer[chan] := per;
  255.       lastVol[chan] := vol;
  256.     END;
  257.   END ModifySound;
  258.  
  259.  
  260. (* Waits until channel 'chan' has finished his sound *)
  261.  
  262.   PROCEDURE WaitSound*(chan: SHORTINT);
  263.   BEGIN
  264.     IF ~CheckChannel(chan) THEN RETURN END;
  265.     IF NOT looped[chan] THEN e.OldWaitIO(ioa0[chan]) END;
  266.   END WaitSound;
  267.  
  268.  
  269. (* Set the Hardware filter on or off *)
  270.  
  271.   PROCEDURE Filter*(on: BOOLEAN);
  272.   BEGIN
  273.     IF on THEN EXCL(hw.ciaa.pra,hw.led)
  274.           ELSE INCL(hw.ciaa.pra,hw.led) END;
  275.   END Filter;
  276.  
  277.  
  278. (* Check, if Filter is on or off *)
  279.  
  280.   PROCEDURE CheckFilter*(): BOOLEAN;
  281.   BEGIN
  282.     RETURN ~(hw.led IN hw.ciaa.pra);
  283.   END CheckFilter;
  284.  
  285.   (* $StackChk= *)
  286.  
  287. BEGIN
  288.  
  289.   priority     := 0;
  290.   abort        := TRUE;
  291.   open[left0]  := FALSE;
  292.   open[right0] := FALSE;
  293.   open[right1] := FALSE;
  294.   open[left1]  := FALSE;
  295.  
  296. CLOSE
  297.  
  298.   CloseChannel(left0);
  299.   CloseChannel(right0);
  300.   CloseChannel(right1);
  301.   CloseChannel(left1);
  302.  
  303. END AudioSupport.
  304.  
  305.  
  306.