*****************************************************************
*								*
*	maestix.library-Demo:	LevelWindow			*
*								*
*****************************************************************
*
*	Programmed by		Richard Körber
*	Date			1995-01-30
*
*****************************************************************
*  This demonstration shows the basic receive functions of the  *
*  maestix library. It allocates the Maestro soundcard, select	*
*  the default  input and  displays the level  of the incoming	*
*  signal using an intuition window.				*
*****************************************************************

		INCDIR	"include:"
		INCLUDE	exec.i			; Library call macros
		INCLUDE	intuition.i
		INCLUDE	graphics.i
		INCLUDE	dos.i
		INCLUDE	maestix.i
		INCLUDE	libraries/maestix.i	;Reference includes
		INCLUDE	intuition/intuition.i
		INCLUDE	dos/dostags.i
		INCLUDE	exec/ports.i

BUFSIZE		EQU	12*1024			;size of FIFO data block
WINDOW_WIDTH	EQU	50			;width of output window

		SECTION text,CODE

*---------------------------------------------------------------*
*	== START OF PROGRAM ==					*
*								*
start	;-- Open all libraries -----------------;
		lea	maestname(PC),a1	;maestix
		moveq	#35,d0			; V35+
		exec	OpenLibrary		; open
		move.l	d0,maestbase		; store base
		beq	error1			; not found!
		lea	intuiname(PC),a1	;intuition
		moveq	#36,d0			; V36+
		exec	OpenLibrary		; open
		move.l	d0,intuibase		; store base
		beq	error2			; not found!
		lea	gfxname(PC),a1		;graphics
		moveq	#36,d0			; V36+
		exec	OpenLibrary		; open
		move.l	d0,gfxbase		; store base
		beq	error3			; not found!
		lea	dosname(PC),a1		;dos
		moveq	#36,d0			; V36+
		exec	OpenLibrary		; open
		move.l	d0,dosbase		; store base
		beq	error4
	;-- Create buffer ----------------------;
		move.l	#BUFSIZE*3,d0		;size of three buffers
		move.l	#$10001,d1		;PUBLIC|CLEAR
		exec	AllocMem
		move.l	d0,buffer
		beq	error5
	;-- Alloc signal bits ------------------;
		sub.l	a1,a1			;get task ptr
		exec	FindTask
		move.l	d0,disptask
		moveq	#-1,d0			;Allocate a signal bit
		exec	AllocSignal
		move.b	d0,dispsigbit
		cmp.b	#-1,d0			;no signals free?
		beq.w	error6
		moveq	#-1,d0			;Allocate a 2nd signal bit
		exec	AllocSignal
		move.b	d0,donesigbit
		cmp.b	#-1,d0			;no signals free?
		beq.w	error7
	;-- Open output window -----------------;
		sub.l	a0,a0			;no newwindow struct
		lea	windowtags(PC),a1	; but loads of tags
		intui	OpenWindowTagList
		move.l	d0,window
		beq	error8
	;-- Launch level task ------------------;
		move.l	#tasktags,d1		;Tags for new task
		dos	CreateNewProc		;create new process
		tst.l	d0			;got the task?
		beq	error9
		moveq	#0,d0			;wait 'till 2nd task setup'd
		move.b	donesigbit(PC),d1	; signal
		bset	d1,d0
		exec	Wait			;wait for this event
	;-- Wait for reply (main loop) ---------;
.mainloop	move.l	window(PC),a0		;window message?
		move.l	wd_UserPort(a0),a0	; ^message port
		exec	GetMsg			; try to get it...
		tst.l	d0			; got one?
		bne.b	.gotwindow		; then evaluate it
		moveq	#0,d0			;create wait mask
		move.b	dispsigbit(PC),d1	; signal for re-displaying
		bset	d1,d0
		move.l	window(PC),a0		; second, from window
		move.l	wd_UserPort(a0),a0	;  message port
		move.b	MP_SIGBIT(a0),d1	; sig bit
		bset	d1,d0			; set this bit
		exec	Wait			;wait for these events
		move.b	dispsigbit(PC),d1	; re-display wanted?
		btst	d1,d0			; test this bit
		beq.b	.mainloop		;not wanted -> main loop
	;---- got a draw signal ----------------;
.drawsig	moveq	#0,d0			;D0: x coordinate left
		move	leftlevel,d1		;D1: left level
		lsr	#8,d1			; (Range 0..128)
		move	oldleft(PC),d2		;D2: old left level
		move	d1,oldleft		; store new "old" level
		bsr	drawlevel		;draw this level
		moveq	#WINDOW_WIDTH/2,d0	;D0: x coordinate left
		move	rightlevel,d1		;D1: right level
		lsr	#8,d1			; (Range 0..128)
		move	oldright(PC),d2		;D2: old right level
		move	d1,oldright		; store new "old" level
		bsr	drawlevel		;draw this level
		bra.b	.mainloop		;and do the mainloop
	;---- got a window event ---------------;
.gotwindow	move.l	d0,a0			;^IDCMP-message -> a0
		cmp.l	#IDCMP_CLOSEWINDOW,im_Class(a0) ;close window?
		bne.b	.mainloop		; no -> continue being idle ;)
	;-- Exit program -----------------------;
exit		move.l	leveltask(PC),a1	;Shut level task
		moveq	#0,d0
		move.b	levelsigbit(PC),d1
		bset	d1,d0
		exec	Signal			; signals the exit
		moveq	#0,d0			;wait 'till 2nd task exited
		move.b	donesigbit(PC),d1	; signal
		bset	d1,d0
		exec	Wait			;wait for this event
error9		move.l	window(PC),a0		;Close output window
		intui	CloseWindow
error8		move.b	donesigbit(PC),d0
		exec	FreeSignal
error7		move.b	dispsigbit(PC),d0	;Get display task signal bit
		exec	FreeSignal
error6		move.l	buffer(PC),a1		;^Buffer
		move.l	#BUFSIZE*3,d0
		exec	FreeMem
error5		move.l	dosbase(PC),a1		;close dos library
		exec	CloseLibrary
error4		move.l	gfxbase(PC),a1		;close graphics library
		exec	CloseLibrary
error3		move.l	intuibase(PC),a1	;close intuition library
		exec	CloseLibrary
error2		move.l	maestbase(PC),a1	;close maestix library
		exec	CloseLibrary
error1		moveq	#0,d0			;Reply 0
		rts				;back to CLI

*-------------------------------------------------------*
* drawlevel	draws the level to window		*
*	-» D0.w	x-coord					*
*	-» D1.w	new level				*
*	-» D2.w	old level				*
*							*
drawlevel	movem.l	a0-a4/d0-d7,-(sp)	;Store all registers
	;-- evaluate "real" coordinates --------;
		move.l	window(PC),a4		;^Window
		moveq	#0,d3			;for calculations
		move.b	wd_BorderLeft(a4),d3	;left border width
		add	d3,d0			;add to x
		move.b	wd_BorderTop(a4),d3	;window title height
		add	#128,d3			;+128 (bottom)
		neg	d1			;d3 - new level
		add	d3,d1
		neg	d2			;d3 - old level
		add	d3,d2
	;-- what colour to use? ----------------;
		moveq	#3,d3			;use blue
		cmp	d2,d1			;compare old vs. new
		beq.b	.done			;old = new -> leave
		blo.b	.colour_ok		;old > new -> blue is ok
		exg	d2,d1			;old < new -> change them
		moveq	#0,d3			;             and use grey
.colour_ok	movem.l	d0-d2,-(sp)		;rescue coordinates
		move	d3,d0			;set A Pen
		move.l	wd_RPort(a4),a1		;^Rast Port
		gfx	SetAPen
		movem.l	(sp)+,d0-d2
	;-- fill this box ----------------------;
		move	d2,d3			;ymax -> D3
		move	d0,d2			;xmax := xmin
		add	#WINDOW_WIDTH/2-1,d2	;       +bar width
		move.l	wd_RPort(a4),a1		;^RastPort
		gfx	RectFill
	;-- done -------------------------------;
.done		movem.l	(sp)+,a0-a4/d0-d7	;Recall all registers
		rts

*---------------------------------------------------------------*
*	== LEVEL PROCESS ==					*
*								*
LevelProc
	;-- Get exiting signal -----------------;
		sub.l	a1,a1			;Get task structure
		exec	FindTask
		move.l	d0,leveltask
		moveq	#-1,d0			;get sig bit
		exec	AllocSignal
		move.b	d0,levelsigbit
		cmp.b	#-1,d0			;got no bit
		beq	.error1
		move.l	disptask(PC),a1		;task is done
		moveq	#0,d0
		move.b	donesigbit(PC),d1
		bset	d1,d0
		exec	Signal			; signals the exit
	;-- Allocate Maestro -------------------;
		sub.l	a0,a0			;no tags
		maest	AllocMaestro
		move.l	d0,maestro		;^Maestro base
		beq	.error2
	;-- Set Modus --------------------------;
		move.l	maestro(PC),a0		;^Maestro base
		lea	modustags(PC),a1	;^Modus tags
		maest	SetMaestro		;set it now
	;-- Read Status ------------------------;
		move.l	maestro(PC),a0		;^Maestro base
		move.l	#MSTAT_Signal,d0	;is input signal ok?
		maest	GetStatus		;get the card status
		tst.l	d0
		beq	.error3
	;-- Create Receive-Messageport ---------;
		exec	CreateMsgPort		;create a messageport
		move.l	d0,rport		; as receive port
		beq	.error4
	;-- Init messages ----------------------;
		move.l	rport(PC),d1		;^Receive Reply Port
		lea	msg1(PC),a0		;^1st Message
		lea	msg2(PC),a1
		lea	msg3(PC),a2
		move.l	buffer(PC),d0		;get buffer ptr
		move.l	d0,(dmn_BufPtr,a0)	; set buffer1
		add.l	#BUFSIZE,d0
		move.l	d0,(dmn_BufPtr,a1)	; set buffer2
		add.l	#BUFSIZE,d0
		move.l	d0,(dmn_BufPtr,a2)	; set buffer 3
		move.l	#BUFSIZE,(dmn_BufLen,a0) ;Set buffer length
		move.l	#BUFSIZE,(dmn_BufLen,a1)
		move.l	#BUFSIZE,(dmn_BufLen,a2)
		move.l	d1,(MN_REPLYPORT,a0)	;Set Reply-Port
		move.l	d1,(MN_REPLYPORT,a1)
		move.l	d1,(MN_REPLYPORT,a2)
		move	#dmn_SIZEOF,(MN_LENGTH,a0) ;Set msg length
		move	#dmn_SIZEOF,(MN_LENGTH,a1)
		move	#dmn_SIZEOF,(MN_LENGTH,a2)
	;-- Start receive process --------------;
		move.l	maestro(PC),a0		;transmit msg to library
		lea	msg1(PC),a1
		maest	ReceiveData		; the 1st (starts receiver!)
		move.l	maestro(PC),a0
		lea	msg2(PC),a1
		maest	ReceiveData		; and the 2nd
		move.l	maestro(PC),a0
		lea	msg3(PC),a1
		maest	ReceiveData		; and the 2nd
	;-- wait for messages ------------------;
.mainloop	move.l	rport(PC),a0		;maestix message?
		exec	GetMsg			; try to get it...
		tst.l	d0			; got one?
		bne.b	.gotmaestro		; then evaluate it
		moveq	#0,d0			;create wait mask
		move.b	levelsigbit(PC),d1	; signal for exiting
		bset	d1,d0
		move.l	rport(PC),a0		; second, from receive port
		move.b	MP_SIGBIT(a0),d1	; sig bit
		bset	d1,d0			; set this bit
		exec	Wait			;wait for these events
		move.b	levelsigbit(PC),d1	; exit forced?
		btst	d1,d0			; test this bit
		beq.b	.mainloop		;not wanted -> main loop
		bra.b	.exit			; wanted -> leave
	;---- got a maestix event --------------;
.gotmaestro	bsr	maestix			;evaluate it
		move.l	disptask(PC),a1		;show new level
		moveq	#0,d0
		move.b	dispsigbit(PC),d1
		bset	d1,d0
		exec	Signal			; signals the exit
		bra.b	.mainloop		;and try again
	;-- Leave task -------------------------;
.exit		move.l	maestro(PC),a0		;Return all messages
		maest	FlushReceive
		move.l	rport(PC),a0		;delete receive port
		exec	DeleteMsgPort
.error4		move.b	levelsigbit(PC),d0	;free signal bit
		exec	FreeSignal
.error3		move.l	maestro(PC),a0		;Set maestro free
		maest	FreeMaestro
.error2		move.l	disptask(PC),a1		;task is done
		moveq	#0,d0
		move.b	donesigbit(PC),d1
		bset	d1,d0
		exec	Signal			; signals the exit
.error1		rts				;done (freed by DOS)

*-------------------------------------------------------*
*  maestix	evaluate maestix event and draw level	*
*	-» D0.l	^Maestro Msg				*
*							*
maestix		move.l	d0,a1			;get ptr
	;-- Get pointers -----------------------;
		move.l	dmn_BufPtr(a1),a0	;a0: ^received data
		move.l	dmn_BufLen(a1),d0
		subq.l	#1,d0
	;-- Get left/right peak level ----------;
		moveq	#0,d6			;Left maximum to here
		moveq	#0,d7			;Right maximum here
.getmax		move	(a0)+,d1		;get one word (left)
		bpl.b	.notneg_l
		neg	d1			;absolute value
.notneg_l	cmp	d6,d1			;new maximum?
		blo.b	.nxtword_l
		move	d1,d6			;store as new maximum
.nxtword_l	move	(a0)+,d1		;get one word (right)
		bpl.b	.notneg_r
		neg	d1			;absolute value
.notneg_r	cmp	d7,d1			;new maximum?
		blo.b	.nxtword_r
		move	d1,d7			;store as new maximum
.nxtword_r	subq.l	#4,d0			;4 bytes less...
		bcc.b	.getmax
		move	d6,leftlevel		;store new levels
		move	d7,rightlevel
	;-- Re-send buffer to maestix ----------;
		move.l	maestro(PC),a0		;Re-send message
		maest	ReceiveData		; to maestix library
	;-- Done -------------------------------;
		rts

*---------------------------------------------------------------*
*	== DATA SECTION ==					*
*								*
disptask	dc.l	0			;^Display task
leveltask	dc.l	0			;^Level task
dispsigbit	dc.b	0			;Display task signal bit
levelsigbit	dc.b	0			;Level task signal bit
donesigbit	dc.b	0			;Display task done sigbit
		even
maestbase	dc.l	0			;^Maestix Lib Base
intuibase	dc.l	0			;^Intuition Lib Base
gfxbase		dc.l	0			;^Graphics Lib Base
dosbase		dc.l	0			;^DOS Lib Base
stdout		dc.l	0			;^Output FH
maestro		dc.l	0			;^Maestro Base
rport		dc.l	0			;^Receive MsgPort
buffer		dc.l	0			;^Data buffer
window		dc.l	0			;^Window structure
msg1		ds.b	dmn_SIZEOF		;^first message
msg2		ds.b	dmn_SIZEOF		;^second message
msg3		ds.b	dmn_SIZEOF		;^third message
leftlevel	dc.w	0			;left real level
rightlevel	dc.w	0			;right real level
oldleft		dc.w	0			;old left level
oldright	dc.w	0			;old right level

modustags	dc.l	MTAG_Input,INPUT_STD	;use standard input
		dc.l	MTAG_Output,OUTPUT_BYPASS
		dc.l	TAG_DONE

tasktags	dc.l	NP_Entry,LevelProc	;<- New process' tags
		dc.l	NP_Priority,25
		dc.l	NP_Name,.name
		dc.l	TAG_DONE
.name		dc.b	"Maestix level process",0
		even

windowtags	dc.l	WA_IDCMP,IDCMP_CLOSEWINDOW ;<- New window's tags
		dc.l	WA_Title,.title
		dc.l	WA_InnerWidth,WINDOW_WIDTH
		dc.l	WA_InnerHeight,129
		dc.l	WA_DragBar,-1
		dc.l	WA_DepthGadget,-1
		dc.l	WA_CloseGadget,-1
		dc.l	WA_Activate,-1
		dc.l	WA_RMBTrap,-1
		dc.l	TAG_DONE
.title		dc.b	"DAT Level",0
		even

maestname	dc.b	"maestix.library",0	;Maestix name
intuiname	dc.b	"intuition.library",0	;Intuition name
gfxname		dc.b	"graphics.library",0	;Graphics name
dosname		dc.b	"dos.library",0		;DOS name
		even

*---------------------------------------------------------------*
*	== END ==						*
*								*
		END
