ùúùú                                        *************************************************************************** 
*                         Example scope for HippoPlayer
*	                        By K-P Koljonen
*******************************************************************************
* Assembles with Asm-One v1.25, at least. Works on all Amiga configurations!


*** Includes:

 	incdir	include:
	include	exec/exec_lib.i
	include	exec/ports.i
	include	exec/types.i
	include	graphics/graphics_lib.i
	include	graphics/rastport.i
	include	intuition/intuition_lib.i
	include	intuition/intuition.i
	incdir

*** Some useful macros

lob	macro
	jsr	_LVO\1(a6)
	endm

lore	macro
	ifc	"\1","Exec"
	ifd	_ExecBase
	ifeq	_ExecBase
	move.l	(a5),a6
	else
	move.l	_ExecBase(a5),a6
	endc
	else
	move.l	4.w,a6
	endc
	else
	move.l	_\1Base(a5),a6
	endc
	jsr	_LVO\2(a6)
	endm

pushm	macro
	ifc	"\1","all"
	movem.l	d0-a6,-(sp)
	else
	movem.l	\1,-(sp)
	endc
	endm

popm	macro
	ifc	"\1","all"
	movem.l	(sp)+,d0-a6
	else
	movem.l	(sp)+,\1
	endc
	endm

push	macro
	move.l	\1,-(sp)
	endm

pop	macro
	move.l	(sp)+,\1
	endm



*** HippoPlayer's port:

	STRUCTURE	HippoPort,MP_SIZE
	LONG		hip_private1	* Private..
	APTR		hip_kplbase	* kplbase address
	WORD		hip_reserved0	* Private..
	BYTE		hip_quit	* If non-zero, we must quit
	BYTE		hip_opencount	* Open count
	BYTE		hip_mainvolume	* Main volume, 0-64
	BYTE		hip_play	* If non-zero, HiP is playing
	BYTE		hip_playertype 	* 33 = Protracker, 49 = PS3M.
	*** Protracker ***
	BYTE		hip_reserved2
	APTR		hip_PTch1	* Protracker channel data for ch1
	APTR		hip_PTch2	* ch2
	APTR		hip_PTch3	* ch3
	APTR		hip_PTch4	* ch4
	*** PS3M ***
	APTR		hip_ps3mleft	* Buffer for the left side
	APTR		hip_ps3mright	* Buffer for the right side
	LONG		hip_ps3moffs	* Playing position
	LONG		hip_ps3mmaxoffs	* Max value for hip_ps3moffs

	BYTE		hip_PTtrigger1
	BYTE		hip_PTtrigger2
	BYTE		hip_PTtrigger3
	BYTE		hip_PTtrigger4

	APTR            hip_private2
	LONG            hip_playtime    * Module time played in secs
	LONG            hip_colordiv    * See below.
	WORD            hip_ps3mrate    * PS3M mixing rate
	LABEL		HippoPort_SIZEOF

	*** PT channel data block
	STRUCTURE	PTch,0
	LONG		PTch_start	* Start address of sample
	WORD		PTch_length	* Length of sample in words
	LONG		PTch_loopstart	* Start address of loop
	WORD		PTch_replen	* Loop length in words
	WORD		PTch_volume	* Channel volume
	WORD		PTch_period	* Channel period
	WORD		PTch_private1	* Private...

*** Dimensions:

WIDTH	=	320	
HEIGHT	=	64

*** Variables:

	rsreset
_ExecBase	rs.l	1
_GFXBase	rs.l	1
_IntuiBase	rs.l	1
port		rs.l	1
owntask		rs.l	1
screenlock	rs.l	1
oldpri		rs.l	1
windowbase	rs.l	1
rastport	rs.l	1
userport	rs.l	1
windowtop	rs	1
windowtopb	rs	1
windowright	rs	1
windowleft	rs	1
windowbottom	rs	1
draw1		rs.l	1
draw2		rs.l	1
omabitmap	rs.b	bm_SIZEOF
size_var	rs.b	0

*** Main program

main	lea	var_b,a5		* Store execbase
	move.l	4.w,a6
	move.l	a6,(a5)
	
	sub.l	a1,a1			* Find our process
	lob	FindTask
	move.l	d0,owntask(a5)

	lea	intuiname(pc),a1	* Open libs
	lore	Exec,OldOpenLibrary
	move.l	d0,_IntuiBase(a5)

	lea 	gfxname(pc),a1		
	lob	OldOpenLibrary
	move.l	d0,_GFXBase(a5)

*** Try to find HippoPlayer's port. If succesful, add 1 to hip_opencount
*** indicating we are using the information in the port.
*** Protect this procedure with Forbid()-Permit()!

	lob	Forbid
	lea	portname(pc),a1
	lob	FindPort
	move.l	d0,port(a5)
	beq.w	exit
	move.l	d0,a0
	addq.b	#1,hip_opencount(a0)	* We are using the port now!
	lob	Permit

*** Get some info about the screen we're running on

	bsr.w	getscreendata

*** Open our window

	lea	winstruc,a0
	lore	Intui,OpenWindow
	move.l	d0,windowbase(a5)
	beq.w	exit
	move.l	d0,a0
	move.l	wd_RPort(a0),rastport(a5)	* Store rastport and userport
	move.l	wd_UserPort(a0),userport(a5)

*** Draw a bevel box

plx1	equr	d4
plx2	equr	d5
ply1	equr	d6
ply2	equr	d7

	moveq   #7,plx1
	move    #332,plx2
	moveq   #13,ply1
	moveq   #80,ply2
	add	windowleft(a5),plx1
	add	windowleft(a5),plx2
	add	windowtop(a5),ply1
	add	windowtop(a5),ply2
	move.l	rastport(a5),a1
	bsr	laatikko1

*** Initialize the bitmap structure

	lea	omabitmap(a5),a0
	moveq	#1,d0			* depth (1 bitplane)
	move	#WIDTH,d1		* width
	move	#HEIGHT,d2		* height
	lore	GFX,InitBitMap
	move.l	#buffer1,omabitmap+bm_Planes(a5) * Plane pointer

	move.l	#buffer1,draw1(a5)	* Buffer pointers for drawing
	move.l	#buffer2,draw2(a5)

*** Set task priority to -30 to prevent messing up with other programs

	move.l	owntask(a5),a1		
	moveq	#-30,d0
	lore	Exec,SetTaskPri
	move.l	d0,oldpri(a5)		* Store the old priority

*** Main loop begins here

loop	move.l	_GFXBase(a5),a6		* Wait a while..
	lob	WaitTOF

	move.l	port(a5),a0		
	tst.b	hip_quit(a0)		* Must we quit?
	bne.b	.x
	tst.b	hip_play(a0)		* Check if HiP is playing
	beq.b	.oh

*** See if we should actually update the window.
	move.l	_IntuiBase(a5),a1
	move.l	ib_FirstScreen(a1),a1
	move.l	windowbase(a5),a0	
	cmp.l	wd_WScreen(a0),a1	* Is our screen on top?
	beq.b	.yes
	tst	sc_TopEdge(a1)	 	* Some other screen is partially on top
	beq.b	.oh		 	* of our screen?
.yes
	bsr.w	dung			* Do the scope
.oh
	move.l	userport(a5),a0		* Get messages from IDCMP
	lore	Exec,GetMsg
	tst.l	d0
	beq.b	loop
	move.l	d0,a1

	move.l	im_Class(a1),d2		
	move	im_Code(a1),d3
	lob	ReplyMsg
	cmp.l	#IDCMP_MOUSEBUTTONS,d2	* Right mousebutton pressed?
	bne.b	.xy
	cmp	#MENUDOWN,d3
	beq.b	.x
.xy	cmp.l	#IDCMP_CLOSEWINDOW,d2	* Should we exit?
	bne.b	loop			* No. Keep loopin'
	
.x	move.l	owntask(a5),a1		* Restore the old priority
	move.l	oldpri(a5),d0
	lore	Exec,SetTaskPri

exit

*** Exit program
	
	move.l	port(a5),d0		* IMPORTANT! Subtract 1 from
	beq.b	.uh0			* hip_opencount when the port is not
	move.l	d0,a0			* needed anymore!
	subq.b	#1,hip_opencount(a0)
.uh0

	move.l	windowbase(a5),d0	* Close the window
	beq.b	.uh1
	move.l	d0,a0
	lore	Intui,CloseWindow
.uh1
	move.l	_IntuiBase(a5),a1	* And the libs
	lore	Exec,CloseLibrary
	move.l	_GFXBase(a5),a1
	lob	CloseLibrary

	moveq	#0,d0			* No error
	rts
	
***** Get some info about the screen we're running on

getscreendata
	move.l	(a5),a0			* Running kick2.0 or newer?
	cmp	#37,LIB_VERSION(a0)
	bhs.b	.new		
	rts				
.new					* Yes.
	
	sub.l	a0,a0			* Default public screen
	lore	Intui,LockPubScreen  	* Kick2.0+ function
	move.l	d0,d7
	beq.b	exit

	move.l	d0,a0
	move.b	sc_BarHeight(a0),windowtop+1(a5) * Palkin korkeus
	move.b	sc_WBorBottom(a0),windowbottom+1(a5)
	move.b	sc_WBorTop(a0),windowtopb+1(a5)
	move.b	sc_WBorLeft(a0),windowleft+1(a5)
	move.b	sc_WBorRight(a0),windowright+1(a5)

	move	windowtopb(a5),d0
	add	d0,windowtop(a5)

	subq	#4,windowleft(a5)		* saattaa mennä negatiiviseksi
	subq	#4,windowright(a5)
	subq	#2,windowtop(a5)
	subq	#2,windowbottom(a5)

	sub	#10,windowtop(a5)
	bpl.b	.o
	clr	windowtop(a5)
.o
	move	windowtop(a5),d0	* Adjust the window size
	add	d0,winstruc+nw_Height
	move	windowleft(a5),d1
	add	d1,winstruc+nw_Width
	move	windowbottom(a5),d3
	add	d3,winstruc+nw_Height

	move.l	d7,a1			* Unlock it. Let's hope it doesn't
	sub.l	a0,a0			* go anywhere before we open our
	lob	UnlockPubScreen		* window ;-)
	rts


** bevelboksit, reunat kaks pixeliä

laatikko1
	moveq	#1,d3
	moveq	#2,d2

	move.l	a1,a3
	move	d2,a4
	move	d3,a2

** valkoset reunat

	move	a2,d0
	move.l	a3,a1
	lore	GFX,SetAPen

	move	plx2,d0		* x1
	subq	#1,d0		
	move	ply1,d1		* y1
	move	plx1,d2		* x2
	move	ply1,d3		* y2
	bsr.w	drawli

	move	plx1,d0		* x1
	move	ply1,d1		* y1
	move	plx1,d2
	addq	#1,d2
	move	ply2,d3
	bsr.w	drawli
	
** mustat reunat

	move	a4,d0
	move.l	a3,a1
	lob	SetAPen

	move	plx1,d0
	addq	#1,d0
	move	ply2,d1
	move	plx2,d2
	move	ply2,d3
	bsr.b	drawli

	move	plx2,d0
	move	ply2,d1
	move	plx2,d2
	move	ply1,d3
	bsr.b	drawli

	move	plx2,d0
	subq	#1,d0
	move	ply1,d1
	addq	#1,d1
	move	plx2,d2
	subq	#1,d2
	move	ply2,d3
	bsr.b	drawli

looex	moveq	#1,d0
	move.l	a3,a1
	jmp	_LVOSetAPen(a6)



drawli	cmp	d0,d2
	bhi.b	.e
	exg	d0,d2
.e	cmp	d1,d3
	bhi.b	.x
	exg	d1,d3
.x	move.l	a3,a1
	move.l	_GFXBase(a5),a6
	jmp	_LVORectFill(a6)




*** Display the scope

* I have two buffers, one for drawing and one for clearing.
* Clearing is done with blitter during which cpu draws into the other
* buffer. The drawn buffer is then dumped into the window using
* BltBitMapRastPort().

dung
	move.l	_GFXBase(a5),a6		* Grab the blitter
	lob	OwnBlitter
	lob	WaitBlit

	move.l	draw2(a5),$dff054	* Clear the drawing area
	move	#0,$dff066
	move.l	#$01000000,$dff040
	move	#HEIGHT*64+WIDTH/16,$dff058

	lob	DisownBlitter		* Free the blitter

	pushm	all
	move.l	port(a5),a0
	cmp.b	#33,hip_playertype(a0)	* Protracker?
	beq.b	.1
	cmp.b	#49,hip_playertype(a0)	* PS3M?
	beq.b	.2
	bra.b	.3
.1	bsr.b	quadrascope		* Quadrascope for PT
	bra.b	.3
.2	bsr.w	multiscope		* Stereoscope for PS3M
.3	popm	all

	movem.l	draw1(a5),d0/d1		* Switch the buffers
	exg	d0,d1
	movem.l	d0/d1,draw1(a5)

	lea	omabitmap(a5),a0	* Set the bitplane pointer
	move.l	d1,bm_Planes(a0)

;	lea	omabitmap(a5),a0	* Copy from bitmap to rastport
	move.l	rastport(a5),a1
	moveq	#0,d0		* source x,y
	moveq	#0,d1
	moveq	#10,d2		* dest x,y
	moveq	#15,d3
	add	windowleft(a5),d2
	add	windowtop(a5),d3
	move	#$c0,d6		* minterm a->d
	move	#WIDTH,d4	* x-size
	move	#HEIGHT,d5	* y-size
	lore	GFX,BltBitMapRastPort	* Zwoosh!
	rts

*** Quarascope routine for Protracker

* This (and the stereoscope) are very unoptimized. The reason for this is
* that unoptimized code is usually easier to understand than optimized code.
* Also this leaves a certain challenge for coders to try to get the loop
* as fast as possible.

quadrascope
	move.l	port(a5),a3
	move.l	hip_PTch1(a3),a3	* Channel 1 data
	move.l	draw1(a5),a0		
	bsr.b	.scope

* WIDTH/8/4 = 10

	move.l	port(a5),a3
	move.l	hip_PTch2(a3),a3
	move.l	draw1(a5),a0
	lea	10(a0),a0		* Position
	bsr.b	.scope

	move.l	port(a5),a3
	move.l	hip_PTch3(a3),a3
	move.l	draw1(a5),a0
	lea	10+10(a0),a0
	bsr.b	.scope

	move.l	port(a5),a3
	move.l	hip_PTch4(a3),a3
	move.l	draw1(a5),a0
	lea	10+10+10(a0),a0
	bsr.b	.scope
	rts

.scope
	tst.l	PTch_loopstart(a3)	* Always check these to avoid
	beq.b	.halt			* enforcer hits!
	move.l	PTch_start(a3),d0
	bne.b	.jolt
.halt	rts

.jolt	
	move.l	d0,a1				* Sample start
	move	PTch_length(a3),d5		* Sample length

	move.l	port(a5),a2		* Get mainvolume
	moveq	#0,d1
	move.b	hip_mainvolume(a2),d1	* (Main volume * sample volume)/64
	mulu	PTch_volume(a3),d1	
	lsr	#6,d1			* Value for scaling the data

	moveq	#0,d0			* X coordinate
	moveq	#80-1,d7		* Loop counter, do 80 pixels
drlo	
	move.b	(a1)+,d2		* Read one byte sample data
	ext	d2			* Sign extend to word
	muls	d1,d2			* Scale according to volume
	asr	#6,d2			* ...
	add	#$80,d2			* Change the sign
	asr	#2,d2			* Scale down to 0-63
	mulu	#WIDTH/8,d2		* Get Y coordinate in the bitplane

	move	d0,d4			* X
	move	d0,d3
	lsr	#3,d4			* X offset in bytes = x-coord/8
	add	d4,d2			* Add to Y
	not	d3			* Plot pixel
	bset	d3,(a0,d2)		* ...

	subq	#1,d5			* Subtract sample length
	bpl.b	.l			* sample end?
	move	PTch_replen(a3),d5	* Get values for loop
	move.l	PTch_loopstart(a3),a1
.l
	addq	#1,d0		* Increase X

	dbf	d7,drlo		* Loop..
	rts



*** Stereoscope for PS3M

multiscope
	move.l	port(a5),a1
	move.l	hip_ps3mleft(a1),a1
	move.l	draw1(a5),a0
	bsr.b	.h

	move.l	port(a5),a1
	move.l	hip_ps3mright(a1),a1
	move.l	draw1(a5),a0
	lea	WIDTH/8/2(a0),a0
	bsr.b	.h
	rts

.h	move.l	port(a5),a2
	move.l	hip_ps3moffs(a2),d5		* Get offset in buffers
	move.l	hip_ps3mmaxoffs(a2),d4		* Get max offset
		
	move	#160-1,d7		* Draw 160 pixels
	moveq	#0,d0			* X coord
.drlo	
	moveq	#0,d2
	move.b	(a1,d5.l),d2		* Get data from mixing buffer
	add.b	#$80,d2
	lsr	#2,d2
	mulu	#WIDTH/8,d2		* Y

	move	d0,d6
	move	d0,d3
	lsr	#3,d6			* X offset in bytes = x-coord/8
	add	d6,d2			
	not	d3			* Plot pixel
	bset	d3,(a0,d2)		* ...

	addq	#1,d0			* Increase x coord
	addq.l	#1,d5			* Increase buffer position
	and.l	d4,d5			* make sure it stays in the buffer

	dbf	d7,.drlo		* Loop
	rts



*******************************************************************************
* Window

wflags set WFLG_SMART_REFRESH!WFLG_DRAGBAR!WFLG_CLOSEGADGET!WFLG_DEPTHGADGET
wflags set wflags!WFLG_RMBTRAP
idcmpflags = IDCMP_CLOSEWINDOW!IDCMP_MOUSEBUTTONS

winstruc
	dc	110,85	* x,y position
winsiz	dc	340,85	* x,y size
	dc.b	2,1	
	dc.l	idcmpflags
	dc.l	wflags
	dc.l	0
	dc.l	0	
	dc.l	.t	* title
	dc.l	0
	dc.l	0	
	dc	0,640	* min/max x
	dc	0,256	* min/max y
	dc	WBENCHSCREEN
	dc.l	0

.t	dc.b	"Example scope",0

intuiname	dc.b	"intuition.library",0
gfxname		dc.b	"graphics.library",0
dosname		dc.b	"dos.library",0
portname	dc.b	"HiP-Port",0
 even


 	section	udnm,bss_p

* Variables

var_b		ds.b	size_var

	section	hihi,bss_c

* GFX buffers

buffer1	ds.b	WIDTH/8*HEIGHT
buffer2	ds.b	WIDTH/8*HEIGHT

 end
