packages feed

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.