language-Modula2-0.1: examples/Modula-2_Libraries/PMOS/sources/general/playlist.mod
IMPLEMENTATION MODULE PlayList;
(********************************************************)
(* *)
(* Playing sounds from a list of buffers *)
(* *)
(* Programmer: P. Moylan, based on ideas *)
(* developed by T. Channon *)
(* Last edited: 27 February 1995 *)
(* Status: Working *)
(* *)
(********************************************************)
FROM SYSTEM IMPORT
(* type *) BYTE;
FROM Types IMPORT
(* type *) FarPointer;
FROM PlayBuff IMPORT
(* proc *) BufferAddress, StartPlaying, Synch0, Synch1, StopPlaying;
FROM Keyboard IMPORT
(* proc *) KeyPressed;
FROM LowLevel IMPORT
(* proc *) FarAddOffset, FarCopy, Far;
FROM Storage1 IMPORT
(* proc *) ALLOCATE, DEALLOCATE;
(************************************************************************)
(* TYPE DEFINITIONS *)
(************************************************************************)
TYPE
(* A BufferList is a linked list of buffers. *)
ListPointer = POINTER TO BlockHeader;
BlockHeader = RECORD
next: ListPointer;
dataptr: OutputBufferPointer;
END (*RECORD*);
BufferList = POINTER TO RECORD
head, tail: ListPointer;
END (*RECORD*);
(************************************************************************)
(* LIST MANIPULATION *)
(************************************************************************)
PROCEDURE CreateList (VAR (*OUT*) L: BufferList);
(* Creates an empty list. *)
BEGIN
NEW (L);
WITH L^ DO
head := NIL; tail := NIL;
END (*WITH*);
END CreateList;
(************************************************************************)
PROCEDURE AddToList (VAR (*INOUT*) L: BufferList; p: OutputBufferPointer);
(* Appends p^ to L. *)
VAR elt: ListPointer;
BEGIN
NEW (elt); elt^.next := NIL; elt^.dataptr := p;
IF L^.head = NIL THEN L^.head := elt
ELSE L^.tail^.next := elt
END (*IF*);
L^.tail := elt;
END AddToList;
(************************************************************************)
PROCEDURE DiscardList (VAR (*INOUT*) L: BufferList);
(* Returns the whole of L to free storage. *)
VAR next: ListPointer;
BEGIN
WHILE L^.head <> NIL DO
DISPOSE (L^.head^.dataptr);
next := L^.head^.next;
DISPOSE (L^.head);
L^.head := next;
END (*WHILE*);
DISPOSE (L);
END DiscardList;
(************************************************************************)
(* PLAYING FROM A LIST OF BUFFERS *)
(************************************************************************)
PROCEDURE PlayFromList (L: BufferList);
(* Real sound play. *)
VAR LP: ListPointer;
OutPtr0, OutPtr1: FarPointer;
BEGIN
(* We have two output buffers, which we fill alternately. The *)
(* following two pointers point to the two buffers. *)
OutPtr0 := BufferAddress();
OutPtr1 := FarAddOffset (OutPtr0, OutputBufferSize);
(* Copy the first data block to buffer 0, then start playing. *)
LP := L^.head;
IF LP = NIL THEN RETURN END(*IF*);
FarCopy (Far(LP^.dataptr), OutPtr0, OutputBufferSize);
LP := LP^.next;
StartPlaying;
LOOP
(* Wait for buffer 1 to become available, then fill it. *)
Synch1;
IF LP = NIL THEN EXIT END(*IF*);
FarCopy (Far(LP^.dataptr), OutPtr1, OutputBufferSize);
LP := LP^.next;
(* Wait for buffer 0 to become available, then fill it. *)
Synch0;
IF (LP = NIL) OR KeyPressed() THEN EXIT END(*IF*);
FarCopy (Far(LP^.dataptr), OutPtr0, OutputBufferSize);
LP := LP^.next;
END (*LOOP*);
StopPlaying;
END PlayFromList;
(************************************************************************)
END PlayList.