home *** CD-ROM | disk | FTP | other *** search
- (*-------------------------------------------------------------------------
- :Program. AudioSupport.mod
- :Contents. Easy sound programming
- :Author. Christian Stiens
- :Address. Heustiege 2, W-4710 Lüdinghausen
- :Copyright. public domain
- :Language. Oberon
- :Translator. Amiga Oberon v2.42d
- :History. V1.0, 25-Aug-90: First release
- :History. V1.1, 24-Jul-91: Oberon, PlayLoopSound, DontAbort, SetPriority
- :History. V1.2, 24-Sep-92: Bug Fixes, CheckFilter
- -------------------------------------------------------------------------*)
-
-
- MODULE AudioSupport;
-
- (* $NilChk- $RangeChk- $OvflChk- $ClearVars- *)
-
- IMPORT
- au : Audio,
- e : Exec,
- es : ExecSupport,
- hw : Hardware,
- rq : Requests,
- sys: SYSTEM;
-
-
- TYPE
- AudioBlock = ARRAY 3 OF au.IOAudio;
-
- CONST
- clock * = 3563220; (* period = clock / sampling frequency *)
-
- left0 * = 0;
- right0 * = 1;
- right1 * = 2;
- left1 * = 3;
-
-
- cantOpen = "Can't open audio channel";
- notOpen = "Audio channel not open";
- illegal = "Illegal audio channel";
-
- VAR
- mp0 : ARRAY 4 OF e.MsgPortPtr;
- ioa0,ioa1,ioa2 : ARRAY 4 OF au.IOAudioPtr;
- open : ARRAY 4 OF BOOLEAN;
- looped : ARRAY 4 OF BOOLEAN;
- lastPer,lastVol: ARRAY 4 OF INTEGER;
- priority : SHORTINT;
- abort : BOOLEAN;
-
-
- (* OpenChannel will open channels with priority pri *)
-
- PROCEDURE SetPriority*(pri: SHORTINT);
- BEGIN
- priority := pri
- END SetPriority;
-
-
- (* Program will not be aborted if channels are not free *)
-
- PROCEDURE DontAbort*;
- BEGIN
- abort := FALSE;
- END DontAbort;
-
-
- (* Open one channel of mask and return its channel number *)
-
- PROCEDURE OpenChannel*(mask: SET): SHORTINT;
- VAR
- allocMask : ARRAY 4 OF SHORTSET;
- chan : SHORTINT;
- i : INTEGER;
- mp : e.MsgPortPtr;
- ioa : UNTRACED POINTER TO AudioBlock;
- BEGIN
- IF mask * {0..3} = {} THEN mask := {0..3} END;
- mp := es.CreatePort("",0);
- IF mp # NIL THEN
- ioa := e.AllocMem(SIZE(AudioBlock),LONGSET{e.memClear,e.public});
- IF ioa # NIL THEN
- ioa^[0].request.message.node.type := e.unknown;
- ioa^[0].request.message.length := SIZE(au.IOAudio);
- ioa^[0].request.message.replyPort := mp;
- i := 0;
- chan := 0; WHILE chan < 4 DO
- IF chan IN mask THEN allocMask[i] := SHORTSET{chan}; INC(i) END;
- INC(chan)
- END;
- ioa^[0].request.message.node.pri := priority;
- ioa^[0].data := sys.ADR(allocMask);
- ioa^[0].length := i;
- ioa^[0].request.command := au.allocate;
- ioa^[0].request.flags := SHORTSET{au.noWait};
- IF e.OpenDevice(au.audioName,0,sys.ADR(ioa^[0]),LONGSET{})=0 THEN
- ioa^[1] := ioa^[0];
- ioa^[2] := ioa^[0];
- CASE sys.VAL(LONGINT,ioa[0].request.unit) OF
- 1: chan := left0 |
- 2: chan := right0 |
- 4: chan := right1 |
- 8: chan := left1
- END;
- mp0[chan] := mp;
- ioa0[chan] := sys.ADR(ioa[0]);
- ioa1[chan] := sys.ADR(ioa[1]);
- ioa2[chan] := sys.ADR(ioa[2]);
- ioa0[chan].data := 0;
- open[chan] := TRUE;
- looped[chan] := FALSE;
- RETURN chan
- END;
- e.FreeMem(ioa,SIZE(AudioBlock));
- END;
- es.DeletePort(mp)
- END;
- rq.Assert(~abort,cantOpen);
- RETURN -1
- END OpenChannel;
-
-
- (* Close the channel chan (which not has to be open). All open
- channels are closed automatic at program end *)
-
- PROCEDURE CloseChannel*(chan: SHORTINT);
- BEGIN
- IF (chan >= 0) & (chan <= 3) & open[chan] THEN
- e.CloseDevice(ioa0[chan]);
- e.FreeMem(ioa0[chan],SIZE(AudioBlock));
- es.DeletePort(mp0[chan]);
- open[chan] := FALSE;
- END
- END CloseChannel;
-
-
- (* $StackChk- *)
-
- PROCEDURE CheckChannel(chan: SHORTINT): BOOLEAN;
- BEGIN
- CASE chan OF
- -1 : rq.Assert(~abort,notOpen); RETURN FALSE |
- 0..3 : IF open[chan] THEN RETURN TRUE
- ELSE rq.Assert(~abort,notOpen); RETURN FALSE END
- ELSE rq.Assert(FALSE,illegal);
- END;
- END CheckChannel;
-
-
- (* Play the sample at address 'sound' (in chip mem) with period 'per'
- (per >= 124), volume 'vol' (0 <= vol <= 64) 'cyc' times (cyc=0 means
- forever) *)
-
- PROCEDURE PlaySound*(chan:SHORTINT; sound:e.APTR; size:LONGINT;
- per,vol,cyc:INTEGER);
- BEGIN
- IF ~CheckChannel(chan) THEN RETURN END;
- IF looped[chan] THEN
- e.AbortIO(ioa1[chan]);
- IF e.GetMsg(mp0[chan])=NIL THEN END;
- END;
- e.AbortIO(ioa0[chan]);
- IF e.GetMsg(mp0[chan])=NIL THEN END;
- ioa0[chan].request.command := e.write;
- ioa0[chan].request.flags := SHORTSET{au.pervol};
- ioa0[chan].data := sound;
- ioa0[chan].length := size;
- ioa0[chan].period := per;
- ioa0[chan].volume := vol;
- ioa0[chan].cycles := cyc;
- es.BeginIO(ioa0[chan]);
- lastPer[chan] := per;
- lastVol[chan] := vol;
- looped[chan] := FALSE;
- END PlaySound;
-
-
- (* Play a looped sound with attack length 'oneShot' and looped
- length 'repeat' *)
-
- PROCEDURE PlayLoopSound*(chan:SHORTINT; sound:e.APTR;
- oneShot,repeat:LONGINT;
- per,vol:INTEGER);
- BEGIN
- IF oneShot = 0 THEN
- PlaySound(chan,sound,repeat,per,vol,0);
- RETURN;
- END;
- IF repeat = 0 THEN
- PlaySound(chan,sound,oneShot,per,vol,1);
- RETURN;
- END;
- IF ~CheckChannel(chan) THEN RETURN END;
- IF looped[chan] THEN
- e.AbortIO(ioa1[chan]);
- IF e.GetMsg(mp0[chan])=NIL THEN END;
- END;
- e.AbortIO(ioa0[chan]);
- IF e.GetMsg(mp0[chan])=NIL THEN END;
- ioa0[chan].request.command := e.write;
- ioa0[chan].request.flags := SHORTSET{au.pervol};
- ioa0[chan].data := sound;
- ioa0[chan].length := oneShot;
- ioa0[chan].period := per;
- ioa0[chan].volume := vol;
- ioa0[chan].cycles := 1;
- es.BeginIO(ioa0[chan]);
- ioa1[chan].request.command := e.write;
- ioa1[chan].request.flags := SHORTSET{};
- ioa1[chan].data := sys.VAL(LONGINT,sound)+oneShot;
- ioa1[chan].length := repeat;
- ioa1[chan].cycles := 0;
- es.BeginIO(ioa1[chan]);
- lastPer[chan] := per;
- lastVol[chan] := vol;
- looped[chan] := TRUE;
- END PlayLoopSound;
-
-
- (* Stop the sound of channel 'chan' *)
-
- PROCEDURE StopSound*(chan: SHORTINT);
- BEGIN
- IF ~CheckChannel(chan) THEN RETURN END;
- IF looped[chan] THEN
- e.AbortIO(ioa1[chan]);
- looped[chan] := FALSE;
- END;
- e.AbortIO(ioa0[chan]);
- END StopSound;
-
-
- (* Returns 'TRUE' if channel 'chan' is playing at this moment *)
-
- PROCEDURE CheckSound*(chan: SHORTINT): BOOLEAN;
- BEGIN
- IF ~CheckChannel(chan) THEN RETURN FALSE END;
- RETURN looped[chan] OR ((ioa0[chan].data#0)&(e.CheckIO(ioa0[chan])=NIL))
- END CheckSound;
-
-
- (* Modifies frequency and volume of a running sound *)
-
- PROCEDURE ModifySound*(chan:SHORTINT; per,vol: INTEGER);
- BEGIN
- IF ~CheckChannel(chan) THEN RETURN END;
- IF (vol#lastVol[chan]) OR (per#lastPer[chan]) THEN
- ioa2[chan].request.command := au.perVol;
- ioa2[chan].period := per;
- ioa2[chan].volume := vol;
- e.OldDoIO(ioa2[chan]);
- lastPer[chan] := per;
- lastVol[chan] := vol;
- END;
- END ModifySound;
-
-
- (* Waits until channel 'chan' has finished his sound *)
-
- PROCEDURE WaitSound*(chan: SHORTINT);
- BEGIN
- IF ~CheckChannel(chan) THEN RETURN END;
- IF NOT looped[chan] THEN e.OldWaitIO(ioa0[chan]) END;
- END WaitSound;
-
-
- (* Set the Hardware filter on or off *)
-
- PROCEDURE Filter*(on: BOOLEAN);
- BEGIN
- IF on THEN EXCL(hw.ciaa.pra,hw.led)
- ELSE INCL(hw.ciaa.pra,hw.led) END;
- END Filter;
-
-
- (* Check, if Filter is on or off *)
-
- PROCEDURE CheckFilter*(): BOOLEAN;
- BEGIN
- RETURN ~(hw.led IN hw.ciaa.pra);
- END CheckFilter;
-
- (* $StackChk= *)
-
- BEGIN
-
- priority := 0;
- abort := TRUE;
- open[left0] := FALSE;
- open[right0] := FALSE;
- open[right1] := FALSE;
- open[left1] := FALSE;
-
- CLOSE
-
- CloseChannel(left0);
- CloseChannel(right0);
- CloseChannel(right1);
- CloseChannel(left1);
-
- END AudioSupport.
-
-
-