;
; "PSMP"  Play Sample
; -------------------
; by Smack/Infect
;
;
; REQUIRES: OS V37+
;
;
; V0.1 (Wednesday 17-Jul-96)
;   -first version
;       play uncompressed IFF-8SVX on all 4 channels
;       audio.device for allocating channels
;       hardware hits: level 4 irq, filter, audio
;
; V0.2 (Tue 01-Oct-96)
;   -support compressed samples (1=Fibonacci Delta, 2=Exponential Delta)
;   -"PLAYBACKRATE" option
;   -exec interrupt handler (INTB_AUD0)
;
; V0.3 (Sat 05-Oct-96)
;   -support XPK compressed samples (using XpkOpen(), XpkRead() etc.)
;   -runtime controls:
;     CTRL-F = toggle filter
;     CTRL-E = repeat mode off
;     CTRL-D = repeat mode on
;     CTRL-C = exit immediately
;
; V0.4 (Thu 10-Oct-96)
;   -replaced 68020+ instructions (MUL/DIV) by utility.library calls
;
; V0.5 (Fri 25-Oct-96)
;   -support stereo samples
;   -better handling of "loading not ready in time"-situations
;    (now there is a silent gap instead of playing "trash")
;   -major internal cleanups
;
; V0.6 (Wed 06-Nov-96)
;   -added Workbench startup
;   -fixed Signal()/Wait() calls (use signalmask instead of signalnumber!)
;   -fixed handling of odd chunksizes
;
; V0.7 (Sat 16-Nov-96)
;   -added "SMALLWINDOW" and "LOADALL" options/tooltypes
;
; V0.8 (Sat 07-Dec-96)
;   -fixed argument parsing
;   -added progressbar
;   -removed "SMALLWINDOW" (by default output to shell and progressbar)
;   -added options "NOPROGRESS", "NOINFO", "PUBSCREEN"
;
; V0.9 (Tue 14-Jan-97)
;   -errors (open file, 8SVX format check) now cause reqtools-filerequester
;   -changed look of progress window slightly
;
; V1.00 (Tue 21-Jan-97)
;   -"locked" progress window doesn't hold loader anymore
;   -added gadgets for REPEAT, INFO and FILTER to the progress window



buffersize=32*1024	;must be below 64K
	incdir	includes:
	include	libraries/xpk.i
	include	os_macros.is
	include	hardware-registers.is
	include	dos/dos.i
	include	dos/dosextens.i


	STRUCTURE myFH,0
	ULONG	mfh_fh		;(must be the first item!!)
	UWORD	mfh_is_xpk	;if non-zero then XPK
	ULONG	mfh_filepos	;XPK only - position in file
	APTR	mfh_xbuff	;XPK only - address of decrunch buffer
	ULONG	mfh_xbuffsize	;XPK only - size of decrunch buffer (=XPK chunksize)
	APTR	mfh_buffpos	;XPK only - current position in decrunch buffer
	ULONG	mfh_buffcontent	;XPK only - current content of decrunch buffer
	APTR	mfh_filename	;(must be the last item!!)
	LABEL	mfh_SIZEOF

	section	aaaa,code
first_
	basereg	first_,a4
	lea	(first_,pc),a4
;--------------------------------------
; open libs
	move.l	(4.w),a6
	move.l	(378,a6),a0	;LibList
	lea	(dosnam,pc),a1
	CALL	FindName		;DOS
	move.l	d0,(dosbase,a4)
	move.l	(378,a6),a0	;LibList
	lea	(gfxnam,pc),a1
	CALL	FindName		;GFX
	move.l	d0,(gfxbase,a4)
	move.l	(378,a6),a0	;LibList
	lea	(intuinam,pc),a1
	CALL	FindName		;INTUITION
	move.l	d0,(intuitionbase,a4)
	lea	(utilnam,pc),a1
	moveq	#37,d0
	CALL	OpenLibrary		;UTILITY
	move.l	d0,(utilitybase,a4)
	beq.w	err_ende
	lea	(iconnam,pc),a1
	moveq	#37,d0
	CALL	OpenLibrary		;ICON
	move.l	d0,(iconbase,a4)
	beq.w	err_ende
	lea	(gtnam,pc),a1
	moveq	#37,d0
	CALL	OpenLibrary		;GADTOOLS
	move.l	d0,(gadtoolsbase,a4)
	beq.w	err_ende


;--------------------------------------
; handle arguments
	sub.l	a1,a1
	CALL	FindTask
	move.l	d0,a5
	tst.l	(172,a5)	;pr_CLI
	bne.b	.from_cli
	lea	(92,a5),a0	;pr_MsgPort
	CALL	WaitPort
	lea	(92,a5),a0	;pr_MsgPort
	CALL	GetMsg			;workbench msg
	move.l	d0,(wbmsg,a4)
	bra.b	.not_cli
.from_cli
	lea	(template,pc),a0
	move.l	a0,d1
	lea	(filenamept,pc),a0
	move.l	a0,d2
	moveq	#0,d3
	CALLDOS	ReadArgs		;read command line args
	move.l	d0,(rdargs,a4)
	bne.b	.args_ok
	lea	(args_start,pc),a0
	lea	(args_end,pc),a1
.argclr	clr.l	(a0)+
	cmp.l	a0,a1
	bne.b	.argclr
.args_ok
.not_cli

	move.l	(wbmsg,pc),d0
	beq.w	.not_wb
	move.l	d0,a5			;a5=wbmsg
	move.l	(36,a5),a3	;sm_ArgList
	move.l	(a3),d1		;wa_Lock
	CALLDOS	CurrentDir
	move.l	d0,(oldcurrdir,a4)
	move.l	(4,a3),a0	;wa_Name
	CALLICON GetDiskObject		;read program's icon
	move.l	d0,d7
	beq.b	.no_icon1
	bsr.b	.read_tooltypes
	move.l	d7,a0
	CALL	FreeDiskObject
.no_icon1
	move.l	(28,a5),d0	;sm_NumArgs
	subq.l	#1,d0
	beq.b	.no_icon2
	move.l	(36,a5),a3	;sm_ArgList
	move.l	(8,a3),d1	;wa_sizeof+wa_Lock
	CALLDOS	CurrentDir
	move.l	(12,a3),a1	;wa_sizeof+wa_Name
	move.l	a1,a0
	move.l	(filenamebuffpt,pc),a2
	move.l	a2,(filenamept,a4)
.cloo	move.b	(a1)+,(a2)+
	bne.b	.cloo
	CALLICON GetDiskObject		;read sample's icon
	move.l	d0,d7
	beq.b	.no_icon2
	bsr.b	.read_tooltypes
	move.l	d7,a0
	CALL	FreeDiskObject
.no_icon2
	bra.w	.not_wb
.read_tooltypes
	move.l	d7,a0
	move.l	($36,a0),a3	;a3=do_ToolTypes
	move.l	a3,a0		;PLAYBACKRATE
	lea	(tt_rate,pc),a1
	CALL	FindToolType
	move.l	d0,d1
	lea	(rate_arg,pc),a0
	move.l	a0,d2
	move.l	a0,(playbackrate,a4)
	CALLDOS	StrToLong
	move.l	a3,a0		;FILTER
	lea	(tt_filter,pc),a1
	CALLICON FindToolType
	move.l	d0,(filter,a4)
	move.l	a3,a0		;REPEAT
	lea	(tt_repeat,pc),a1
	CALL	FindToolType
	move.l	d0,(repeat,a4)
	move.l	a3,a0		;INFO
	lea	(tt_info,pc),a1
	CALL	FindToolType
	move.l	d0,(info,a4)
	move.l	a3,a0		;LOADALL
	lea	(tt_loadall,pc),a1
	CALL	FindToolType
	move.l	d0,(loadall,a4)
	move.l	a3,a0		;NOPROGRESS
	lea	(tt_noprogress,pc),a1
	CALL	FindToolType
	move.l	d0,(noprogress,a4)
	move.l	a3,a0		;NOINFO
	lea	(tt_noinfo,pc),a1
	CALL	FindToolType
	move.l	d0,(noinfo,a4)
	move.l	a3,a0		;PUBSCREEN
	lea	(tt_pubscreen,pc),a1
	CALL	FindToolType
	tst.l	d0
	beq.b	.nops
	move.l	d0,a0
	lea	(psnam),a1
	move.l	a1,(pubscrnam,a4)
.pscopy	move.b	(a0)+,(a1)+
	bne.b	.pscopy
.nops	rts
.not_wb

	move.l	(noinfo,pc),d0
	bne.b	.noinfo
	CALLDOS	Output
	move.l	d0,(output,a4)		;output
	bne.b	.output_ok
	lea	(connam,pc),a0
	move.l	a0,d1
	move.l	#MODE_OLDFILE,d2
	CALL	Open			;open own window
	move.l	d0,(output,a4)
	move.l	d0,(conwindow,a4)
.output_ok
	move.l	(output,pc),d1
	lea	(maintxt,pc),a0
	move.l	a0,d2
	CALLDOS	FPutS			;print title string
	tst.l	(wbmsg,a4)
	bne.b	.info
	tst.l	(rdargs,a4)
	bne.b	.info
	move.l	(output,pc),d1
	lea	(argwarntxt,pc),a0
	move.l	a0,d2
	CALL	FPutS
	bra.b	.info
.noinfo
	clr.l	(info,a4)
.info
	move.l	(playbackrate,pc),d0
	beq.b	.norate_arg
	move.l	d0,a0
	move.l	(a0),d0
	ble.b	.norate_arg
	move.l	d0,(rate_arg,a4)
.norate_arg

	tst.l	(filenamept,a4)
	bne.w	skipfilerequester
dofilerequester
	moveq	#38,d0
	lea	(rtnam,pc),a1
	CALLEXEC OpenLibrary		;V38 reqtools.library
	tst.l	d0
	beq.w	ende
	move.l	d0,a6
	moveq	#0,d0		;RT_FILEREQ
	sub.l	a0,a0
	CALL	rtAllocRequestA
	tst.l	d0
	beq.w	err_ende
	move.l	d0,a5
	lea	(filereqtags,pc),a0
	move.l	a5,a1
	move.l	(lbuffpt,pc),a2
	lea	(filereqtitle,pc),a3
	CALL	rtFileRequestA
	move.l	(16,a5),a0	;filereq->dir
	move.l	(filenamebuffpt,pc),a1
	clr.l	(a1)
.dircop	move.b	(a0)+,(a1)+
	bne.b	.dircop
	move.l	a6,d7
	move.l	(filenamebuffpt,pc),d1
	move.l	(lbuffpt,pc),d2
	move.l	#1024,d3
	CALLDOS	AddPart
	move.l	d7,a6
	move.l	(filenamebuffpt,pc),(filenamept,a4)
	move.l	a5,a1
	CALL	rtFreeRequest
	move.l	a6,a1
	CALLEXEC CloseLibrary
	move.l	(filenamebuffpt,pc),a0
	tst.l	(a0)
	beq.w	ende			;cancelled or empty string
skipfilerequester

;--------------------------------------
; init file
	move.l	(dosbase,pc),a6
	move.l	#"FORM",d6		;!!!!!
	move.l	#"8SVX",d7		;!!!!!

	move.l	(loadall,pc),d0
	beq.w	.notloadall

	;----LOADALL
	move.l	(filenamept,pc),d1
	move.l	#MODE_OLDFILE,d2
	CALL	Open
	move.l	d0,d5
	beq.w	dofilerequester
	move.l	d5,d1
	move.l	(buff1pt,pc),d2
	move.l	d2,a5
	moveq	#32,d3
	CALL	Read
	move.l	d0,d4		;read error
	move.l	d5,d1
	move.l	(buff2pt,pc),d2
	CALL	ExamineFH
	move.l	d5,d1
	move.l	d0,d5		;examine error
	CALL	Close
	tst.l	d4
	bmi.w	ifferr		;ENDSTREAMCH
	tst.l	d5
	beq.w	ifferr		;DOSFALSE

	move.l	(buff1pt,pc),a0
	cmp.l	#"XPKF",(a0)
	bne.b	.notxpk
	add	#16,a0
.notxpk	cmp.l	(a0),d6
	bne.w	ifferr
	cmp.l	(8,a0),d7	;FORM 8SVX ?
	bne.w	ifferr

	move.l	(buff2pt,pc),a0
	move.l	(108+16,a0),d5	;fib.Size
	ble.w	ifferr
	move.l	d5,d0
	moveq	#0,d1
	CALLEXEC AllocVec
	move.l	d0,(loadallvec,a4)
	bne.b	.memok
	clr.l	(loadall,a4)
	bra.b	.notloadall

.memok	move.l	(filenamept,pc),d1
	move.l	#MODE_OLDFILE,d2
	CALLDOS	Open
	move.l	d0,d4
	beq.w	err_ende
	move.l	d0,d1
	move.l	(loadallvec,pc),d2
	move.l	d5,d3
	CALL	Read
	move.l	d4,d1
	move.l	d0,d4		;read error
	CALL	Close
	cmp.l	d4,d5
	bne.w	readerr
	move.l	#XPK_InBuf,(xpkopentags,a4)
	move.l	(loadallvec,pc),(xpkopentags+4,a4)
	move.l	#XPK_InLen,(xot_inlen,a4)
	move.l	d5,(xot_inlen+4,a4)
.notloadall

	;----not LOADALL
xopen_again
	lea	(smpfh1,pc),a0
	move.l	(filenamept,pc),(mfh_filename,a0)
	bsr.w	_XOpen
	tst.l	d0
	beq.b	openok
handle_xopen_error
	addq.l	#1,d0
	bne.b	not___1
	bra.w	dofilerequester

putstr	move.l	a0,d2
	move.l	(output,pc),d1
	CALLDOS	FPutS
	bra.w	err_ende

not___1
	addq.l	#1,d0
	bne.b	not___2
	lea	(xpknam,pc),a1		;-2
	moveq	#2,d0
	CALLEXEC OpenLibrary
	move.l	d0,(xpkbase,a4)
	bne.b	xopen_again
	lea	(xpkliberrtxt,pc),a0
	bra.b	putstr
not___2
	addq.l	#1,d0
	bne.b	not___3
xpkerr	lea	(xpkerrtxt,pc),a0	;-3,  global "print xpk error"
	move.l	a0,d2
	lea	(xpkerrtxtargs,pc),a0
	move.l	a0,d3
	move.l	(output,pc),d1
	CALLDOS	VFPrintf
	bra.w	err_ende
not___3
	addq.l	#1,d0
	bne.w	err_ende
memerr	lea	(memerrtxt,pc),a0	;-4,  global "print mem error"
	bra.b	putstr
openok
	;---check IFF-8SVX
	lea	(smpfh1,pc),a0
	move.l	(buff1pt,pc),d2
	moveq	#12,d3
	bsr.w	_XRead
	cmp.l	d0,d3
	bne.b	ifferr
	move.l	(buff1pt,pc),a0
	cmp.l	(a0),d6			;!!!!!
	bne.b	ifferr
	cmp.l	(8,a0),d7		;!!!!!
	beq.b	form_ok
ifferr	bra.w	dofilerequester
form_ok
	;---read VHDR, CHAN, move to beginning of BODY
chunkloop
	lea	(smpfh1,pc),a0
	move.l	(buff1pt,pc),d2
	moveq	#8,d3
	bsr.w	_XRead
	cmp.l	d0,d3
	bne.b	ifferr
	move.l	(buff1pt,pc),a0

	cmp.l	#"VHDR",(a0)		;---VHDR
	bne.b	.not_vhdr
	move.l	a0,d2
	move.l	(4,a0),d3
	lea	(smpfh1,pc),a0
	bsr.w	_XRead			;len should be 20
	cmp.l	d0,d3
	bne.b	ifferr
	move.l	(buff1pt,pc),a0
	move	(12,a0),(rate+2,a4)		;vh_SamplesPerSec
	move.b	(15,a0),(compression+1,a4)	;vh_Compression
	bra.b	chunkloop
.not_vhdr
	cmp.l	#"CHAN",(a0)		;---CHAN
	bne.b	.not_chan
	move.l	a0,d2
	move.l	(4,a0),d3
	lea	(smpfh1,pc),a0
	bsr.w	_XRead			;len should be 4
	cmp.l	d0,d3
	bne.b	ifferr
	move.l	(buff1pt,pc),a0
	cmp.l	#6,(a0)
	bne.b	.not_st
	st	(is_stereo,a4)
.not_st	bra.b	chunkloop
.not_chan
	cmp.l	#"BODY",(a0)		;---BODY
	beq.b	.is_body

	move.l	(4,a0),d2		;---skip other chunks
	addq.l	#1,d2
	lsr.l	#1,d2
	add.l	d2,d2			;round up to even length!!
	moveq	#OFFSET_CURRENT,d3
	lea	(smpfh1,pc),a0
	bsr.w	_XSeek
	bra.w	chunkloop

.is_body
	move.l	(4,a0),d0
	move.l	d0,(bodyend,a4)
	move.l	d0,(bodylen,a4)
	lea	(smpfh1,pc),a0
	moveq	#0,d2
	moveq	#OFFSET_CURRENT,d3
	bsr.w	_XSeek
	move.l	d0,(bodystart,a4)
	move.l	d0,(currpos,a4)
	add.l	d0,(bodyend,a4)

	move.l	(output,pc),d1
	lea	(filetxt,pc),a0
	move.l	a0,d2
	lea	(filenamept,pc),a0
	move.l	a0,d3
	CALLDOS	VFPrintf

;--------------------------------------
; calc some things and print info text
	tst.l	(rate_arg,a4)	;option PLAYBACKRATE?
	bne.b	.pbrate_arg
	move.l	(rate,pc),(rate_arg,a4)
.pbrate_arg
	move.l	(4.w),a1
	move.l	(568,a1),d7	;ex_EClockFrequency
	move.l	d7,d0
	lsl.l	#2,d7
	add.l	d0,d7		;ex_EClockFrequency*5
	move.l	(rate_arg,pc),d6
	move.l	d7,d0
	move.l	d6,d1
	CALLUTIL UDivMod32
	lsr.l	#1,d6
	cmp.l	d6,d1		;remainder
	ble.b	.no_r_u
	addq	#1,d0		;round result up
.no_r_u	move	d0,(rate_amiga,a4)
	move.l	d0,d1
	move.l	d7,d0
	CALL	UDivMod32
	move.l	d0,(rate_play,a4)

	move.l	(bodylen,pc),d0
	tst	(compression,a4)
	beq.b	.nocomp
	add.l	d0,d0
.nocomp	tst	(is_stereo,a4)
	beq.b	.noster
	lsr.l	#1,d0
.noster	move.l	d0,(bytestoplay,a4)
	move.l	(rate_play,pc),d7
	move.l	d7,d1
	CALL	UDivMod32
	divu	#60,d0
	move	d0,(minutes,a4)
	swap	d0
	move	d0,(seconds,a4)
	move.l	#1000,d0
	CALL	UMult32
	move.l	d7,d1
	CALL	UDivMod32
	move	d0,(millisec,a4)

	lea	(comp0txt,pc),a0	;none
	move	(compression,pc),d0
	beq.b	.cstr
	lea	(comp1txt,pc),a0	;Fibonacci Delta
	subq	#1,d0
	beq.b	.cstr
	lea	(comp2txt,pc),a0	;Exponential Delta
	subq	#1,d0
	beq.b	.cstr
	lea	(comperrtxt,pc),a0	;unknown compression
	bra.w	putstr
.cstr	move.l	a0,(compstr,a4)

	lea	(monotxt,pc),a0
	tst	(is_stereo,a4)
	beq.b	.ststr
	lea	(stereotxt,pc),a0
.ststr	move.l	a0,(stereostr,a4)

	move.l	(bodylen,pc),d0
	moveq	#10,d1
	lsr.l	d1,d0
	move.l	d0,(bodylenKB,a4)

	tst	(smpfh1+mfh_is_xpk,a4)
	beq.b	.not_xpk
	move.l	(smpfh1+mfh_fh,pc),a0
	move.l	(xf_Packer,a0),(packername,a4)
	move.l	(xf_Ratio,a0),(packerratio,a4)
	move.l	(xf_NLen,a0),d0
	moveq	#10,d1
	lsr.l	d1,d0
	move.l	d0,(packerchszKB,a4)
	lea	(xpktxt,pc),a0
	move.l	a0,d2
	lea	(xpktxt_args,pc),a0
	move.l	a0,d3
	move.l	(output,pc),d1
	CALLDOS	VFPrintf
.not_xpk
	lea	(infotxt,pc),a0
	move.l	a0,d2
	lea	(infotxt_args,pc),a0
	move.l	a0,d3
	move.l	(output,pc),d1
	CALLDOS	VFPrintf


	tst.l	(info,a4)
	bne.w	ende

;--------------------------------------
; setup audio
	CALLEXEC CreateMsgPort
	move.l	d0,(msgport,a4)
	beq.b	.audioerr

	move.l	d0,a0		;msg port
	moveq	#62,d0		;ioa_sizeof
	CALL	CreateIORequest
	move.l	d0,(ioreq,a4)
	beq.b	.audioerr

	move.l	d0,a1
	move.b	#127,(9,a1)	;channel pri
	lea	(channelmap,pc),a0
	move.l	a0,(34,a1)	;ioa_data
	moveq	#2,d0
	move.l	d0,(38,a1)	;ioa_length
	lea	(audionam,pc),a0
	moveq	#0,d0		;unit
	moveq	#0,d1		;flags
	CALL	OpenDevice
	tst.l	d0
	bne.b	.audioerr
	st	(audioopen,a4)
	bra.b	.audiook
.audioerr
	lea	(audioerrtxt,pc),a0
	bra.w	putstr
.audiook
qqq1

;--------------------------------------
; fill buffer the first time
	move.l	(bodyend,pc),d0
	sub.l	(bodystart,pc),d0
	move.l	#buffersize*2,d3
	move	(compression,pc),d7
	beq.b	.nocom1
	lsr.l	#1,d3		;half loading size
.nocom1
	tst	(is_stereo,a4)
	beq.b	.noster
	lsr.l	#1,d0
.noster
	cmp.l	d3,d0
	bge.b	.large

	st	(playmode,a4)		;small
	move.l	d0,d3
	tst	d7
	beq.b	.nocom2
	add.l	d0,d0		;double playing size
.nocom2	move.l	d0,(buff1size,a4)
	move.l	d0,(buff2size,a4)
	move.l	(buff1pt,pc),(buff2pt,a4)
	bra.b	.readit
.large	lsr.l	#1,d3			;large
.readit
	lea	(smpfh1,pc),a0
	move.l	(buff1pt,pc),d2
	tst	d7
	beq.b	.nocom3
	move.l	(lbuffpt,pc),d2
.nocom3	bsr.w	_XRead
	cmp.l	d0,d3
	bne.b	readerr
	add.l	d0,(currpos,a4)
	bra.b	qqq2
readerr
	tst.l	(xpk_error,a4)
	bne.w	xpkerr
	lea	(readerrtxt,pc),a0
	bra.w	putstr
qqq2
	move	d7,d1			;comp_type
	beq.b	.nocom4
	move.l	(lbuffpt,pc),a0		;inbuf
	move.l	(buff1pt,pc),a1		;outbuf
	move	(a0)+,d2		;initial value
	move	d2,(a1)+
	subq.l	#2,d0			;inlen
	bsr.w	decompress_4bit_delta
	move.b	d0,(initial_value,a4)
.nocom4

;--------------------------------------
; prepare stereo
	tst	(is_stereo,a4)
	beq.w	.no_stereo

	lea	(smpfh2,pc),a0
	move.l	(filenamept,pc),(mfh_filename,a0)
	bsr.w	_XOpen			;open file a second time
	tst.l	d0
	bne.w	handle_xopen_error

	move.l	#buffersize*2,d0
	moveq	#2,d1			;MEMF_CHIP
	CALLEXEC AllocVec		;alloc second chip buffer
	move.l	d0,(buffspt,a4)
	beq.w	memerr
	move.l	d0,(buffs1pt,a4)
	add.l	#buffersize,d0
	move.l	d0,(buffs2pt,a4)

	lea	(smpfh2,pc),a0
	move.l	(bodylen,pc),d2
	lsr.l	#1,d2
	add.l	(bodystart,pc),d2
	move.l	d2,(stereostart,a4)
	moveq	#OFFSET_CURRENT,d3
	bsr.w	_XSeek			;seek to half of BODY

	move.l	(buff1size,pc),(buffs1size,a4)
	move.l	(buff2size,pc),(buffs2size,a4)
	tst	(playmode,a4)
	beq.b	.large
	move.l	(buffs1pt,pc),(buffs2pt,a4)
.large
	move.l	(buffs1size,pc),d3
	move.l	(buffs1pt,pc),d2
	move	(compression,pc),d7
	beq.b	.nocom1
	lsr.l	#1,d3		;half loading size
	move.l	(lbuffpt,pc),d2
.nocom1
	lea	(smpfh2,pc),a0
	bsr.w	_XRead
	cmp.l	d0,d3
	bne.w	readerr

	move	d7,d1			;comp_type
	beq.b	.nocom3
	move.l	(lbuffpt,pc),a0		;inbuf
	move.l	(buffs1pt,pc),a1	;outbuf
	move	(a0)+,d2		;initial value
	move	d2,(a1)+
	subq.l	#2,d0			;inlen
	bsr.w	decompress_4bit_delta
	move.b	d0,(initial_value2,a4)
.nocom3
.no_stereo
	
;--------------------------------------
; init progress indicator window
	move.l	(noprogress,pc),d0
	bne.w	noprogresswin
	move.l	(filenamept,pc),d1
	CALLDOS	FilePart
	move.l	d0,(filepart,a4)
	move.l	(pubscrnam,pc),d0
	beq.b	.defps
	move.l	d0,a0
	CALLINT	LockPubScreen
	move.l	d0,(pubscreen,a4)
	bne.b	.psok
	move.l	(output,pc),d1
	lea	(pubscrtxt,pc),a0
	move.l	a0,d2
	lea	(pubscrnam,pc),a0
	move.l	a0,d3
	CALLDOS	VFPrintf
.defps	sub.l	a0,a0
	CALLINT	LockPubScreen		;lock default public screen
	move.l	d0,(pubscreen,a4)
	beq.w	err_ende
.psok	move.l	d0,a0
	move.l	a0,(owt_pubscr+4,a4)

	move.l	(40,a0),a0	;screen.sc_Font
	moveq	#0,d1
	move	(4,a0),d1	;screen.sc_Font->ta_YSize
	move.l	d1,(fontheight,a4)
	lsl.l	#3,d1
	move.l	d1,(owt_height+4,a4)	;8*fontheight

	move.l	(pubscreen,pc),a1
	add	#84,a1		;screen.sc_RastPort
	move.l	a1,d7
	lea	(timetxt,pc),a0
	moveq	#timetxtlen,d0
	CALLGFX	TextLength		;fit timetxt-width
	move.l	d0,(timetxtwidth,a4)
	add.l	d0,d0
	cmp.l	(owt_width+4,pc),d0
	bmi.b	.nw1
	move.l	d0,(owt_width+4,a4)
.nw1	move.l	(filepart,pc),a0
	move.l	a0,a2
	moveq	#-1,d0
.count	addq.l	#1,d0
	tst.b	(a2)+
	bne.b	.count
	move.l	d0,(filepartlen,a4)
	move.l	d7,a1
	CALL	TextLength		;fit filename-width
	move.l	d0,(filepartwidth,a4)
	add.l	d0,d0
	cmp.l	(owt_width+4,pc),d0
	bmi.b	.nw2
	move.l	d0,(owt_width+4,a4)
.nw2
	move.l	(pubscreen,pc),a0
	move	(12,a0),d0	;screen.sc_Width
	sub	(owt_width+6,pc),d0
	bmi.b	.nwc
	lsr	#1,d0
	move	d0,(owt_left+6,a4)
.nwc	move	(14,a0),d0	;screen.sc_Height
	sub	(owt_height+6,pc),d0
	bmi.b	.nhc
	lsr	#1,d0
	move	d0,(owt_top+6,a4)
.nhc
	sub.l	a0,a0
	lea	(openwindow_tags,pc),a1
	CALLINT	OpenWindowTagList
	move.l	d0,(intuiwindow,a4)
	beq.w	err_ende
	move.l	d0,a5
	CALLEXEC Disable
	move.l	(86,a5),a5	;window.wd_UserPort
	move.b	#1,(14,a5)	;window.wd_UserPort->mp_Flags=PA_SOFTINT
	lea	(idcmp_softint,pc),a1
	move.l	a1,(16,a5)	;window.wd_UserPort->mp_SigTask/mp_SoftInt
	CALL	Enable

	move.l	(intuiwindow,pc),a5
	move.l	(50,a5),d7	;window.wd_RPort !!!
	move.l	d7,a1
	moveq	#1,d0		;JAM2
	CALLGFX	SetDrMd
	move.l	d7,a1
	moveq	#0,d0
	CALL	SetBPen
	move.l	d7,a1
	move.l	(pubscreen,pc),a0
	move.l	(84+52,a0),a0	;screen.RastPort.TextFont
	CALL	SetFont

	move.l	d7,a1
	moveq	#3,d0
	CALL	SetAPen
	move.l	d7,a1
	moveq	#0,d0
	moveq	#0,d1
	moveq	#0,d2
	move	(112,a5),d2	;window.wd_GZZWidth
	moveq	#0,d3
	move	(114,a5),d3	;window.wd_GZZHeight
	CALL	RectFill

	moveq	#0,d0
	move	(112,a5),d0	;window.wd_GZZWidth
	subq	#1,d0
	move.l	d0,d2		;!!!
	move.l	d0,d1
	divu	#25,d1
	swap	d1
	clr	d1
	swap	d1
	move.l	d1,(pbleft,a4)
	sub.l	d1,d0
	move.l	d0,(pbright,a4)
	move.l	(fontheight,pc),d0
	move.l	d0,d1
	move.l	d0,d3
	lsr.l	#1,d3		;!!!
	add.l	d1,d1
	add.l	d3,d1
	move.l	d1,(pbtop,a4)
	add.l	d0,d1		;!!!
	move.l	d1,(pbbot,a4)
	sub.l	(timetxtwidth,pc),d2	;!!!
	lsr.l	#1,d2
	move.l	d2,(timetxtx,a4)
	add.l	d0,d1			;!!!
	add.l	d3,d1
	move.l	d1,(timetxty,a4)

	move.l	d7,a1
	move.l	(pbleft,pc),d0
	lsr.l	#1,d0
	move.l	d0,a3
	move.l	d0,(gadget_left,a4)
	move.l	(fontheight,pc),d1
	lsr.l	#1,d1
	move.l	d1,d5
	move.l	(pbright,pc),d2
	add.l	d0,d2
	move.l	d2,d4
	move.l	d2,(gadget_right,a4)
	move.l	(timetxty,pc),d3
	add.l	d1,d3
	move.l	d3,d6
	CALL	EraseRect

	move.l	d7,a1
	moveq	#2,d0
	CALL	SetAPen
	move.l	d7,a1
	move.l	a3,d0
	move.l	d6,d1
	CALL	Move
	move.l	d7,a1
	move.l	a3,d0
	move.l	d5,d1
	CALL	Draw
	move.l	d7,a1
	move.l	d4,d0
	move.l	d5,d1
	CALL	Draw
	move.l	d7,a1
	moveq	#1,d0
	CALL	SetAPen
	move.l	d7,a1
	move.l	d4,d0
	move.l	d6,d1
	CALL	Draw
	move.l	d7,a1
	move.l	a3,d0
	move.l	d6,d1
	CALL	Draw

	moveq	#0,d0
	move	(112,a5),d0	;window.wd_GZZWidth
	sub.l	(filepartwidth,pc),d0
	bge.b	.fpw
	moveq	#0,d0
.fpw	lsr.l	#1,d0		;x
	move.l	(fontheight,pc),d1
	add.l	d1,d1		;y
	move.l	d7,a1
	CALL	Move
	move.l	d7,a1
	move.l	(filepart,pc),a0
	move.l	(filepartlen,pc),d0
	CALL	Text

	move.l	(pbright,pc),d1
	sub.l	(pbleft,pc),d1
	subq.l	#2,d1
	move.l	d1,(pbwidth,a4)
	move.l	(bytestoplay,pc),d0
	CALLUTIL UDivMod32
	move.l	d0,(bytestoplay,a4)
	moveq	#"0",d3
	moveq	#0,d1
	moveq	#1,d2
	move	(minutes,pc),d0
.min	subq	#1,d0
	bmi.b	.mine
	abcd	d2,d1
	bra.b	.min
.mine	move	d1,d0
	lsr	#4,d0
	add	d3,d0
	move.b	d0,(timetxt_tm,a4)
	and	#$f,d1
	add	d3,d1
	move.b	d1,(timetxt_tm+1,a4)
	moveq	#0,d1
	move	(seconds,pc),d0
.sec	subq	#1,d0
	bmi.b	.sece
	abcd	d2,d1
	bra.b	.sec
.sece	move	d1,d0
	lsr	#4,d0
	add	d3,d0
	move.b	d0,(timetxt_ts,a4)
	and	#$f,d1
	add	d3,d1
	move.b	d1,(timetxt_ts+1,a4)

	move.l	d7,a1
	move.l	(timetxtx,pc),d0
	move.l	(timetxty,pc),d1
	CALLGFX	Move
	move.l	d7,a1
	lea	(timetxt,pc),a0
	moveq	#timetxtlen,d0
	CALL	Text

	move.l	d7,a1
	move.l	(pbleft,pc),d0
	move.l	(pbbot,pc),d1
	CALL	Move
	move.l	d7,a1
	move.l	(pbleft,pc),d0
	move.l	(pbtop,pc),d1
	CALL	Draw
	move.l	d7,a1
	move.l	(pbright,pc),d0
	move.l	(pbtop,pc),d1
	CALL	Draw
	move.l	d7,a1
	moveq	#2,d0
	CALL	SetAPen
	move.l	d7,a1
	move.l	(pbright,pc),d0
	move.l	(pbbot,pc),d1
	CALL	Draw
	move.l	d7,a1
	move.l	(pbleft,pc),d0
	move.l	(pbbot,pc),d1
	CALL	Draw



	move.l	(pubscreen,pc),a0
	sub.l	a1,a1
	CALLGT	GetVisualInfoA
	move.l	d0,(visualinfo,a4)
	beq.w	err_ende
	lea	(g_glist,pc),a0
	CALL	CreateContext
	move.l	d0,(g_context,a4)
	beq.w	err_ende

	move.l	(pubscreen,pc),a0
	move.l	(40,a0),(ng_txtattr_,a4)	;screen.sc_TextAttr
	move.l	(visualinfo,pc),(ng_visinfo_,a4)

	lea	(gtxt_filter,pc),a0
	move.l	a0,(ng_txt_,a4)
	moveq	#$10,d0			;PLACETEXT_IN
	move.l	d0,(ng_flags_,a4)
	move	#FILTER_ID,(ng_gid_,a4)
	move	(gadget_left+2,pc),(ng_left_,a4)

	move.l	(intuiwindow,pc),a1
	move.l	(50,a1),a1		;RastPort
	lea	(gtxt_filter,pc),a0
	moveq	#gtxt_filter_chars,d0
	CALLGFX	TextLength
	addq	#8,d0
	move	d0,(ng_width_,a4)

	move.l	(fontheight,pc),d0
	move.l	d0,d1
	addq	#4,d0
	move	d0,(ng_height_,a4)
	lsr.l	#1,d1
	add.l	d1,d0
	subq	#2,d0
	neg	d0
	move	d0,(ng_top_,a4)
	moveq	#1,d0			;BUTTON_KIND
	move.l	(g_context,pc),a0	;prev. gadget
	lea	(newgadget_,pc),a1
	lea	(newgadgettags,pc),a2
	CALLGT	CreateGadgetA
	move.l	d0,(g_filter,a4)
	beq.w	err_ende
	move.l	d0,a0
	or	#8,(12,a0)		;GFLG_RELBOTTOM
	and	#~1,(14,a0)		;not GACT_RELVERIFY
	or	#$102,(14,a0)		;GACT_TOGGLESELECT + GACT_IMMEDIATE
	move.l	(filter,pc),d0
	beq.b	.nofilter
	or	#$80,(12,a0)		;GFLG_SELECTED
.nofilter

	lea	(gtxt_repeat,pc),a0
	move.l	a0,(ng_txt_,a4)
	moveq	#$10,d0			;PLACETEXT_IN
	move.l	d0,(ng_flags_,a4)
	move	#REPEAT_ID,(ng_gid_,a4)

	move.l	(intuiwindow,pc),a1
	move.l	(50,a1),a1		;RastPort
	lea	(gtxt_repeat,pc),a0
	moveq	#gtxt_repeat_chars,d0
	CALLGFX	TextLength
	addq	#8,d0
	move	d0,(ng_width_,a4)

	move	(gadget_right+2,pc),d0
	addq	#1,d0
	sub	(ng_width_,pc),d0
	move	d0,(ng_left_,a4)
	moveq	#1,d0			;BUTTON_KIND
	move.l	(g_filter,pc),a0	;prev. gadget
	lea	(newgadget_,pc),a1
	lea	(newgadgettags,pc),a2
	CALLGT	CreateGadgetA
	move.l	d0,(g_repeat,a4)
	beq.w	err_ende
	move.l	d0,a0
	or	#8,(12,a0)		;GLFG_RELBOTTOM
	and	#~1,(14,a0)		;not GACT_RELVERIFY
	or	#$102,(14,a0)		;GACT_TOGGLESELECT + GACT_IMMEDIATE
	move.l	(repeat,pc),d0
	beq.b	.norepeat
	or	#$80,(12,a0)		;GFLG_SELECTED
.norepeat

	lea	(gtxt_info,pc),a0
	move.l	a0,(ng_txt_,a4)
	moveq	#$10,d0			;PLACETEXT_IN
	move.l	d0,(ng_flags_,a4)
	move	#INFO_ID,(ng_gid_,a4)

	move.l	(intuiwindow,pc),a1
	move.l	(50,a1),a1		;RastPort
	lea	(gtxt_info,pc),a0
	moveq	#gtxt_info_chars,d0
	CALLGFX	TextLength
	addq	#8,d0
	move	d0,(ng_width_,a4)
	move	(gadget_right+2,pc),d1
	move	(gadget_left+2,pc),d2
	sub	d2,d1
	lsr	#1,d1
	add	d2,d1
	lsr	#1,d0
	sub	d0,d1
	move	d1,(ng_left_,a4)
	moveq	#1,d0			;BUTTON_KIND
	move.l	(g_repeat,pc),a0	;prev. gadget
	lea	(newgadget_,pc),a1
	lea	(newgadgettags_e,pc),a2
	CALLGT	CreateGadgetA
	move.l	d0,(g_info,a4)
	beq.w	err_ende
	move.l	d0,a0
	or	#8,(12,a0)		;GLFG_RELBOTTOM

	move.l	(intuiwindow,pc),a5
	move.l	a5,a0
	move.l	(g_glist,pc),a1
	moveq	#-1,d0
	moveq	#-1,d1
	sub.l	a2,a2
	CALLINT	AddGList
	move.l	a5,a1
	move.l	(g_glist,pc),a0
	sub.l	a2,a2
	CALL	RefreshGadgets

noprogresswin



;--------------------------------------
; setup timing
	moveq	#-1,d0
	CALLEXEC AllocSignal
	move.l	d0,(signal,a4)		;own signal
	moveq	#-1,d1
	cmp.l	d0,d1
	beq.w	err_ende
	sub.l	a1,a1
	CALL	FindTask
	move.l	d0,(mytask,a4)		;own task
	move.l	d0,a1
	moveq	#10,d0
	CALL	SetTaskPri
	move.l	d0,(oldpri,a4)

	lea	($dff000),a5
	move	#$780,d0
	move	d0,(intena,a5)
	move	d0,(intreq,a5)		;audio irqs off
	moveq	#7,d0		;INTB_AUD0
	lea	(int_struct,pc),a1
	CALL	SetIntVector
	move.l	d0,(oldlevel4,a4)
	move	#$8080,d0
	move	d0,(intena,a5)
	move	d0,(intreq,a5)		;audio irq 0 on

;--------------------------------------
mainloop
	clr	(read_busy,a4)
	move.l	#$0000f000,d7	;break signals
	move.l	(signal,pc),d1	;signalnumber
	moveq	#1,d0
	lsl.l	d1,d0
	or.l	d7,d0		;signalmask
	CALLEXEC Wait
	move.l	d0,d6
	and.l	d7,d0
	beq.b	.nobreak

	lea	(new_gadget_state,pc),a5

	rol	#4,d0		;lsr #12
	moveq	#8,d1		;CTRL-F
	and	d0,d1
	beq.b	.no_ctrlf
	st	(a5)
	lea	($bfe001),a0
	lea	(filter,pc),a1
	tst.l	(a1)
	bne.b	.filter_is_on
	st	(a1)
	bclr	#1,(a0)		;filter on
	bra.b	.no_ctrlf
.filter_is_on
	clr.l	(a1)
	bset	#1,(a0)		;filter off
.no_ctrlf
	moveq	#4,d1		;CTRL-E
	and	d0,d1
	beq.b	.no_ctrle
	st	(a5)
	clr.l	(repeat,a4)	;repeat mode off
.no_ctrle
	moveq	#2,d1		;CTRL-D
	and	d0,d1
	beq.b	.no_ctrld
	st	(a5)
	st	(repeat,a4)	;repeat mode on
.no_ctrld
	moveq	#1,d1		;CTRL-C
	and	d0,d1
	bne.w	ende
	not.l	d7
	and.l	d7,d6
	beq.b	mainloop	;no other signal (for loading)
.nobreak
	tst	(playmode,a4)
	bne.b	mainloop	;small sample


	moveq	#0,d7		;!!!!
	st	(read_busy,a4)

	move.l	d7,-(a7)
	move.l	(intuiwindow,pc),d7	;---progress indicator
	beq.w	.noprogress

	move.l	(do_info_req,pc),d0
	beq.b	.not_inforeq
	move.l	(info_req_window,pc),d0
	bne.b	.not_inforeq
	lea	(easystruct_,pc),a1
	lea	(info_req_gad,pc),a0
	move.l	a0,(16,a1)	;gadgets text
	lea	(info_req_msg,pc),a0
	move.l	a0,(12,a1)	;message text
	lea	(info_req_args,pc),a3
	move.l	a3,a2
	lea	(vstr+6,pc),a0
	move.l	a0,(a2)+
	move.l	(filenamept,pc),(a2)+
	move.l	(rate_play,pc),(a2)+
	move.l	(minutes,pc),(a2)+
	move	(millisec,pc),(a2)+
	move.l	(intuiwindow,pc),a0
	sub.l	a2,a2
	CALLINT	BuildEasyRequestArgs
	move.l	d0,(info_req_window,a4)
	bne.b	.not_inforeq
	clr.l	(do_info_req,a4)	;if it didn't open
.not_inforeq

	move.l	(info_req_window,pc),d6
	beq.b	.not_inforeq_open
	move.l	d6,a0
	sub.l	a1,a1
	moveq	#0,d0
	CALLINT	SysReqHandler
	tst.l	d0
	bmi.b	.not_inforeq_open
	move.l	d6,a0
	CALL	FreeSysRequest
	clr.l	(info_req_window,a4)
	clr.l	(do_info_req,a4)
.not_inforeq_open

	move.l	d7,a0
	move.l	(124,a0),a5	;window.wd_WLayer
	CALLGFX	AttemptLockLayerROM
	tst.l	d0
	beq.w	.noprogress
	lea	(new_gadget_state,pc),a0
	tst.l	(a0)
	beq.b	.notgad
	clr.l	(a0)
	move.l	(g_filter,pc),a0
	move	#$80,d1		;GFLG_SELECTED
	move.l	(filter,pc),d0
	beq.b	.fg_off
	or	d1,(12,a0)
	bra.b	.fg_
.fg_off	not	d1
	and	d1,(12,a0)
.fg_	move.l	(g_repeat,pc),a0
	move	#$80,d1		;GFLG_SELECTED
	move.l	(repeat,pc),d0
	beq.b	.rg_off
	or	d1,(12,a0)
	bra.b	.rg_
.rg_off	not	d1
	and	d1,(12,a0)
.rg_	move.l	d7,a1
	move.l	(g_glist,pc),a0
	sub.l	a2,a2
	CALLINT	RefreshGadgets
.notgad
	move.l	d7,a0
	move.l	(50,a0),a5	;window.wd_RPort
	move.l	(playedbytes,pc),d0
	move.l	(bytestoplay,pc),d1
	CALLUTIL UDivMod32
	move.l	(pbwidth,pc),d1
	cmp.l	d0,d1
	bge.b	.prwok
	move.l	d1,d0
.prwok	move.l	d0,d7
	move.l	(pbcurrent,pc),d6
	move.l	d0,(pbcurrent,a4)
	move.l	(pbleft,pc),d0
	addq.l	#1,d0
	add.l	d0,d6
	add.l	d0,d7
	move.l	(gfxbase,pc),a6	;!!!
	cmp.l	d6,d7		;clear?
	bge.b	.prdraw
	moveq	#1,d6
	add.l	(pbleft,pc),d6
	move.l	a5,a1
	moveq	#0,d0
	CALL	SetAPen
	move.l	a5,a1
	move.l	(pbleft,pc),d0
	move.l	(pbtop,pc),d1
	move.l	(pbright,pc),d2
	move.l	(pbbot,pc),d3
	addq.l	#1,d0
	addq.l	#1,d1
	subq.l	#1,d2
	subq.l	#1,d3
	CALL	RectFill
.prdraw	move.l	a5,a1		;draw
	moveq	#3,d0
	CALL	SetAPen
	move.l	d6,d0
	move.l	(pbtop,pc),d1
	addq.l	#1,d1
	move.l	d7,d2
	move.l	(pbbot,pc),d3
	subq.l	#1,d3
	CALL	RectFill

.prtime	move.l	(playedbytes,pc),d0
	move.l	(rate_play,pc),d1
	CALLUTIL UDivMod32
	divu	#60,d0
	move	d0,(timemin,a4)
	swap	d0
	move	d0,(timesec,a4)
	moveq	#"0",d7
	moveq	#0,d1
	moveq	#1,d2
.prsec	subq	#1,d0
	bmi.b	.prsece
	abcd	d2,d1
	bra.b	.prsec
.prsece	move	d1,d0
	lsr	#4,d0
	add	d7,d0
	move.b	d0,(timetxt_cs,a4)
	and	#$f,d1
	add	d7,d1
	move.b	d1,(timetxt_cs+1,a4)
	swap	d0
	moveq	#0,d1
.prmin	subq	#1,d0
	bmi.b	.prmine
	abcd	d2,d1
	bra.b	.prmin
.prmine	move	d1,d0
	lsr	#4,d0
	add	d7,d0
	move.b	d0,(timetxt_cm,a4)
	and	#$f,d1
	add	d7,d1
	move.b	d1,(timetxt_cm+1,a4)

	move.l	a5,a1
	moveq	#1,d0
	CALLGFX	SetAPen
	move.l	a5,a1
	move.l	(timetxtx,pc),d0
	move.l	(timetxty,pc),d1
	CALL	Move
	move.l	a5,a1
	lea	(timetxt,pc),a0
	moveq	#timetxtlen,d0
	CALL	Text

	move.l	(intuiwindow,pc),a0
	move.l	(124,a0),a5	;window.wd_WLayer
	CALL	UnlockLayerROM
.noprogress
	move.l	(a7)+,d7



	move.l	(bodyend,pc),d0
	tst	(is_stereo,a4)
	beq.b	.noste1
	lsr.l	#1,d0
.noste1
	sub.l	(currpos,pc),d0
	bmi.w	readerr
	bgt.b	.noseek

	;---seek to start
	lea	(oneshot_last,pc),a0
	st	(a0)
	tst.l	(repeat,a4)
	beq.w	mainloop
	clr	(a0)

	clr.l	(playedbytes,a4)
	clr	(timemin,a4)
	clr	(timesec,a4)

	lea	(smpfh1,pc),a0
	move.l	(bodystart,pc),d2
	move.l	d2,(currpos,a4)
	moveq	#OFFSET_BEGINNING,d3
	bsr.w	_XSeek			;seek to start of BODY
	tst.l	d0
	bmi.w	readerr

	tst	(is_stereo,a4)
	beq.b	.nost
	lea	(smpfh2,pc),a0
	move.l	(stereostart,pc),d2
	moveq	#OFFSET_BEGINNING,d3
	bsr.w	_XSeek			;seek to half of BODY
	tst.l	d0
	bmi.w	readerr
.nost	move.l	#buffersize,d0
	moveq	#1,d7		;!!!!
.noseek

	;---read and decompress
	move.l	#buffersize,d3
	move.l	(buff1pt,pc),d2
	tst	(compression,a4)
	beq.b	.nocom1
	lsr.l	#1,d3
	move.l	(lbuffpt,pc),d2
.nocom1
	cmp.l	d0,d3
	ble.b	.read
	move.l	d0,d3
.read	lea	(smpfh1,pc),a0
	bsr.w	_XRead
	cmp.l	d0,d3
	bne.w	readerr
	add.l	d0,(currpos,a4)
	move.l	d0,(buff1size,a4)
	move	(compression,pc),d1	;comp_type
	beq.b	.check_stereo
	add.l	d0,(buff1size,a4)
	move.l	(lbuffpt,pc),a0		;inbuf
	move.l	(buff1pt,pc),a1		;outbuf
	move.b	(initial_value,pc),d2
	tst.l	d7		;!!!!
	beq.b	.not_start
	move	(a0)+,d2		;initial value
	move	d2,(a1)+
	subq.l	#2,d0			;inlen
.not_start
	bsr.w	decompress_4bit_delta
	move.b	d0,(initial_value,a4)

.check_stereo
	tst	(is_stereo,a4)
	beq.w	mainloop
	lea	(smpfh2,pc),a0
	move.l	(buff1size,pc),d3	;len from other side
	move.l	(buffs1pt,pc),d2
	tst	(compression,a4)
	beq.b	.nocom2
	lsr.l	#1,d3
	move.l	(lbuffpt,pc),d2
.nocom2	bsr.w	_XRead
	cmp.l	d0,d3
	bne.w	readerr
	move.l	d0,(buffs1size,a4)
	move	(compression,pc),d1	;comp_type
	beq.w	mainloop
	add.l	d0,(buffs1size,a4)
	move.l	(lbuffpt,pc),a0		;inbuf
	move.l	(buffs1pt,pc),a1	;outbuf
	move.b	(initial_value2,pc),d2
	tst.l	d7		;!!!!
	beq.b	.not_start2
	move	(a0)+,d2		;initial value
	move	d2,(a1)+
	subq.l	#2,d0			;inlen
.not_start2
	bsr.w	decompress_4bit_delta
	move.b	d0,(initial_value2,a4)
	bra.w	mainloop






;--------------------------------------
; some global routines


check_idcmp	;(called from MsgPort-SoftInt)
	movem.l	d1-a6,-(a7)
	move.l	(intuiwindow,pc),a0
	move.l	(86,a0),a0	;window.wd_UserPort
	CALLEXEC GetMsg
	tst.l	d0
	beq.w	.exit
	move.l	d0,a5
	move.l	(20,a5),d0	;msg.Class
	move	#$200,d1
	and	d0,d1
	beq.b	.notclosegadget
	moveq	#1,d0
	ror	#4,d0			;Ctrl-C
	move.l	(mytask,pc),a1
	CALL	Signal
	bra.b	.reply
.notclosegadget
	moveq	#$20,d1
	and	d0,d1
	beq.b	.notgadgetdown
	move.l	(28,a5),a0	;msg.IAddress
	move	(38,a0),d0	;gadget.GadgetID
	move	(12,a0),d1	;gadget.Flags
	cmp	#FILTER_ID,d0
	bne.b	.notfiltergadget
	lea	(filter,pc),a1
	lea	($bfe001),a2
	move	#$80,d0		;GFLG_SELECTED
	and	d1,d0
	bne.b	.filtergadgetoff
	st	(a1)
	bclr	#1,(a2)		;filter on
	bra.b	.reply
.filtergadgetoff
	clr.l	(a1)
	bset	#1,(a2)		;filter off
	bra.b	.reply
.notfiltergadget
	cmp	#REPEAT_ID,d0
	bne.b	.notrepeatgadget
	lea	(repeat,pc),a1
	move	#$80,d0		;GFLG_SELECTED
	and	d1,d0
	beq.b	.repeatgadgetoff
	clr.l	(a1)		;repeat off
	bra.b	.reply
.repeatgadgetoff
	st	(a1)		;repeat on
	bra.b	.reply
.notrepeatgadget
.notgadgetdown
	moveq	#$40,d1
	and	d0,d1
	beq.b	.notgadgetup
	move.l	(28,a5),a0	;msg.IAddress
	move	(38,a0),d0	;gadget.GadgetID
	cmp	#INFO_ID,d0
	bne.b	.notinfogadget
	lea	(do_info_req,pc),a0
	st	(a0)
	;;bra.b	.reply
.notinfogadget
.notgadgetup
.reply	move.l	a5,a1
	CALL	ReplyMsg
.exit	movem.l	(a7)+,d1-a6
	moveq	#0,d0
	rts




mylevel4	;-----------
	movem.l	d1-a6,-(a7)
	lea	($dff000),a5
	lea	(first_,pc),a4

	lea	($bfe001),a0
	tst.l	(filter,a4)
	beq.b	.filteroff
	bclr	#1,(a0)		;filter on
	bra.b	.skipfilter
.filteroff
	bset	#1,(a0)		;filter off
.skipfilter
	move	#$00ff,(adkcon,a5)
	move	(rate_amiga,pc),d0
	move	d0,(aud0per,a5)
	move	d0,(aud1per,a5)
	move	d0,(aud2per,a5)
	move	d0,(aud3per,a5)

	moveq	#64,d0
	tst	(read_busy,a4)
	beq.b	.volume
	moveq	#0,d0
.volume	move	d0,(aud0vol,a5)
	move	d0,(aud1vol,a5)
	move	d0,(aud2vol,a5)
	move	d0,(aud3vol,a5)
	tst	d0
	beq.w	.end

	move	#$000f,(dmacon,a5)	;dma off
	move.l	(buff1pt,pc),d0
	move.l	d0,d1
	move.l	(buff1size,pc),d2
	move.l	d2,d3
	lsr.l	#1,d2
	tst	(is_stereo,a4)
	beq.b	.noster
	move.l	(buffs1pt,pc),d1
	move.l	(buffs1size,pc),d3
.noster	lsr.l	#1,d3
	move.l	d0,(aud0lch,a5)	
	move.l	d1,(aud1lch,a5)
	move.l	d1,(aud2lch,a5)
	move.l	d0,(aud3lch,a5)
	move	d2,(aud0len,a5)
	move	d3,(aud1len,a5)
	move	d3,(aud2len,a5)
	move	d2,(aud3len,a5)

	moveq	#8,d0
	bsr.b	.wait_hsync
	move	#$800f,(dmacon,a5)	;dma on
	moveq	#8,d0
	bsr.b	.wait_hsync

	move.l	(buff2size,pc),d0
	add.l	d0,(playedbytes,a4)

	move.l	(buff1pt,pc),d0
	move.l	(buff2pt,pc),(buff1pt,a4)
	move.l	d0,(buff2pt,a4)
	move.l	(buff1size,pc),d0
	move.l	(buff2size,pc),(buff1size,a4)
	move.l	d0,(buff2size,a4)

	move.l	(buffs1pt,pc),d0
	move.l	(buffs2pt,pc),(buffs1pt,a4)
	move.l	d0,(buffs2pt,a4)
	move.l	(buffs1size,pc),d0
	move.l	(buffs2size,pc),(buffs1size,a4)
	move.l	d0,(buffs2size,a4)

	move.l	(repeat,pc),d7		;loop
	tst	(playmode,a4)
	beq.b	.large

	tst	(firstirq,a4)
	bne.b	.notfirst
	st	(firstirq,a4)
	bra.b	.end

.wait_hsync	;-----------------
; d0=number_of_syncs   a5=$dff000
.outer	move.b	(6,a5),d1
.inner	cmp.b	(6,a5),d1
	beq.b	.inner
	subq	#1,d0
	bgt.b	.outer
	rts

.notfirst
	moveq	#1,d0
	ror	#4,d0
	tst.l	d7			;loop?
	beq.b	.do_signal		;no -> break
	bra.b	.end			;yes -> no signal
.large
	move.l	(signal,pc),d1
	moveq	#1,d0
	lsl.l	d1,d0
	tst	(oneshot_last,a4)
	beq.b	.do_signal
	tst.l	d7
	bne.b	.do_signal
	moveq	#1,d0
	ror	#4,d0			;break signals

.do_signal
	move.l	(mytask,pc),a1
	CALLEXEC Signal
.end
	move	#$780,(intreq,a5)
	movem.l	(a7)+,d1-a6
	moveq	#0,d0
	nop
	rts



;***Decompress_4bit_Delta*******************************************
; parameters:
;  d0 - inlen (must be EVEN)
;  d1 - comp_type (1 or 2)
;  d2 - initial value
;  a0 - inbuff
;  a1 - outbuff
; result:
;  d0 - last value (initial value for next call)
decompress_4bit_delta
	movem.l	d1-a6,-(a7)
	lea	(fib_tab,pc),a2
	subq.b	#1,d1
	beq.b	.fib
	lea	(exp_tab,pc),a2
.fib	moveq	#0,d1
	moveq	#$0f,d5
.loop	move.b	(a0)+,d1
	move.l	d1,d3
	lsr	#4,d1
	add.b	(a2,d1.l),d2
	move.b	d2,d4
	lsl	#8,d4
	and	d5,d3
	add.b	(a2,d3.l),d2
	move.b	d2,d4
	swap	d4
	move.b	(a0)+,d1
	move.l	d1,d3
	lsr	#4,d1
	add.b	(a2,d1.l),d2
	move.b	d2,d4
	lsl	#8,d4
	and	d5,d3
	add.b	(a2,d3.l),d2
	move.b	d2,d4
	move.l	d4,(a1)+	;LONG writes to the fucking slow ChipRAM
	subq.l	#2,d0		;inlen is EVEN
	bgt.b	.loop
	move.l	d2,d0
	movem.l	(a7)+,d1-a6
	rts
fib_tab	dc.b	-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21
exp_tab	dc.b	-128,-64,-32,-16,-8,-4,-2,-1,0,1,2,4,8,16,32,64




;***_XOpen**********************************************************
; parameters:
;  a0 - myFH (mfh_filename must have been initialized!)
; result:
;  d0 - 0=OK, other=ERROR
; 
; -DOSBase must be valid
; -if file starts with "XPKF" and XPKBase=NULL
;    -> result=-2 -> call _XOpen again when xpkmaster.library was opened
_xopen
	movem.l	d1-a6,-(a7)
	move.l	a0,a5

	moveq	#mfh_SIZEOF-5,d0	;don't clear mfh_filename !!
.clrloo	clr.b	(a0)+
	dbf	d0,.clrloo

	move.l	(loadall,pc),d0
	beq.b	.notloadall
	move.l	(loadallvec,pc),a0
	cmp.l	#"XPKF",(a0)
	beq.b	.xla
	bra.w	.end_ok
.notloadall

	move.l	(mfh_filename,a5),d1
	move.l	#MODE_OLDFILE,d2
	CALLDOS	Open
	move.l	d0,(a5)
	bne.b	.open_ok
	moveq	#-1,d0			;-1=DOS_OPEN_ERROR
	bra.w	.exit
.open_ok
	move.l	d0,d1
	lea	(.xpkf_test,pc),a0
	move.l	a0,d2
	moveq	#4,d3
	CALL	Read

	move.l	(.xpkf_test,pc),d0
	cmp.l	#"XPKF",d0
	beq.b	.is_xpk
	move.l	(a5),d1
	moveq	#0,d2
	moveq	#OFFSET_BEGINNING,d3
	CALL	Seek
	bra.b	.end_ok

.is_xpk
	move.l	(a5),d1
	CALL	Close
	clr.l	(a5)
.xla	move.l	(xpkbase,pc),d0
	bne.b	.xpklib_ok
	moveq	#-2,d0			;-2=XPKMASTER_NOT_OPEN
	bra.b	.exit
.xpklib_ok
	move.l	d0,a6
	move.l	a5,a0
	lea	(xpkopentags,pc),a1
	tst.l	(loadall,a4)
	bne.b	.la
	move.l	(mfh_filename,a5),(4,a1)
.la	CALL	XpkOpen
	move.l	d0,(xpk_error,a4)
	beq.b	.xpkopen_ok
	moveq	#-3,d0			;-3=XPK_ERROR
	bra.b	.exit
.xpkopen_ok
	st	(mfh_is_xpk,a5)
	move.l	(a5),a0
	move.l	(xf_NLen,a0),d0
	move.l	d0,(mfh_xbuffsize,a5)
	add.l	#XPK_MARGIN,d0
	moveq	#0,d1
	CALLEXEC AllocVec
	move.l	d0,(mfh_xbuff,a5)
	bne.b	.end_ok
	moveq	#-4,d0			;-4=MEM_ERROR
	bra.b	.exit

.end_ok	moveq	#0,d0
.exit	movem.l	(a7)+,d1-a6
	rts

.xpkf_test	dc.l	0
xpkopentags	dc.l	XPK_InName,0	;to be patched!
		dc.l	XPK_GetError,xpkerrormsg
		dc.l	XPK_ShortError,-1
xot_inlen	dc.l	0,0,0




;***_XRead**********************************************************
; parameters:
;  a0 - myFH
;  d2 - buffer
;  d3 - len
; result:
;  d0 - bytes read (0=EOF, <0=ERROR)
_xread
	movem.l	d1-a6,-(a7)
	move.l	a0,a5		;myFH
	tst	(mfh_is_xpk,a5)
	bne.b	.is_xpk
	move.l	(loadall,pc),d0
	beq.b	.nla
	move.l	(mfh_filepos,a5),a0
	add.l	(loadallvec,pc),a0
	move.l	d2,a1
	move.l	d3,d0
	add.l	d0,(mfh_filepos,a5)
	CALLEXEC CopyMem
	move.l	d3,d0
	bra.b	.exit
.nla	move.l	(a0),d1		;mfh_fh
	CALLDOS	Read
.exit	movem.l	(a7)+,d1-a6
	rts
.is_xpk	move.l	d2,d6	;buf
	move.l	d3,d7	;len
	moveq	#0,d5	;already read
.xloop	tst.l	d7
	bgt.b	.go_on
.eof	move.l	d5,d0
	add.l	d0,(mfh_filepos,a5)
	bra.b	.exit
.go_on	move.l	(mfh_buffcontent,a5),d0
	ble.b	.read
	sub.l	d0,d7
	bge.b	.copy
	add.l	d0,d7
	move.l	d7,d0
	moveq	#0,d7
.copy	move.l	(mfh_buffpos,a5),a0
	move.l	d6,a1
	add.l	d0,d5
	add.l	d0,(mfh_buffpos,a5)
	add.l	d0,d6
	sub.l	d0,(mfh_buffcontent,a5)
	CALLEXEC CopyMem
	bra.b	.xloop
.read	move.l	(a5),a0		;mfh_fh
	move.l	(mfh_xbuff,a5),a1
	move.l	a1,(mfh_buffpos,a5)
	move.l	(mfh_xbuffsize,a5),d0
	CALLXPK	XpkRead
	move.l	d0,(mfh_buffcontent,a5)
	beq.b	.eof
	bgt.b	.xloop
	move.l	d0,(xpk_error,a4)
	bra.b	.exit


;***_XSeek**********************************************************
; parameters:
;  a0 - myFH
;  d2 - newpos (only positive numbers (forward seeking) supported)
;  d3 - offset (only OFFSET_BEGINNING and OFFSET_CURRENT supported)
; result:
;  d0 - oldpos (<0=ERROR)
_xseek
	movem.l	d1-a6,-(a7)
	move.l	a0,a5			;myFH
	tst	(mfh_is_xpk,a5)
	bne.b	.is_xpk
	move.l	(loadall,pc),d0
	beq.b	.nla
	move.l	(mfh_filepos,a5),d0	;oldpos
	tst.l	d3
	beq.b	.offcur
	clr.l	(mfh_filepos,a5)
.offcur	add.l	d2,(mfh_filepos,a5)
	bra.b	.exit
.nla	move.l	(a5),d1
	CALLDOS	Seek
.exit	movem.l	(a7)+,d1-a6
	rts
.is_xpk	move.l	d2,d6			;newpos
	move.l	(mfh_filepos,a5),d7	;oldpos
	tst.l	d3			;offset
	beq.b	.seek_loop		;OFFSET_CURRENT

	move.l	(a5),a0
	CALLXPK	XpkClose
	clr.l	(a5)
	clr.l	(mfh_filepos,a5)
	clr.l	(mfh_buffcontent,a5)
	move.l	a5,a0
	lea	(xpkopentags,pc),a1
	tst.l	(loadall,a4)
	bne.b	.la
	move.l	(mfh_filename,a5),(4,a1)
.la	CALL	XpkOpen			;"seek" to beginning
	move.l	d0,(xpk_error,a4)
	beq.b	.seek_loop
	moveq	#-1,d0			;ERROR
	bra.b	.exit
.seek_loop
	tst.l	d6			;newpos
	bgt.b	.do_seek
	move.l	d7,d0			;return old position
	bra.b	.exit
.do_seek
	move.l	(mfh_buffcontent,a5),d0
	ble.b	.read
	cmp.l	d6,d0
	bmi.b	.not_enough
	sub.l	d6,(mfh_buffcontent,a5)
	add.l	d6,(mfh_buffpos,a5)
	add.l	d6,(mfh_filepos,a5)
	moveq	#0,d6
	bra.b	.seek_loop
.not_enough
	sub.l	d0,d6
	add.l	d0,(mfh_filepos,a5)
.read
	move.l	(a5),a0
	move.l	(mfh_xbuff,a5),a1
	move.l	a1,(mfh_buffpos,a5)
	move.l	(mfh_xbuffsize,a5),d0
	CALLXPK	XpkRead
	move.l	d0,(mfh_buffcontent,a5)
	beq.b	.eof
	bgt.b	.seek_loop
	move.l	d0,(xpk_error,a4)
	bra.w	.exit
.eof	moveq	#-1,d0			;ERROR (EOF)
	bra.w	.exit



;***_XClose*********************************************************
; parameters:
;  a0 - myFH (should be safe to call several times unlike DOS/Close()!!)
_xclose
	movem.l	d1-a6,-(a7)
	move.l	a0,a5

	move.l	(a5),d1
	beq.b	.no_fh
	clr.l	(a5)
	tst	(mfh_is_xpk,a5)
	bne.b	.is_xpk
	CALLDOS	Close
	bra.b	.no_fh
.is_xpk	move.l	(xpkbase,pc),d0
	beq.b	.no_fh
	move.l	d0,a6
	move.l	d1,a0
	CALL	XpkClose
.no_fh
	lea	(mfh_xbuff,a5),a0
	move.l	(a0),d0
	beq.b	.no_xbuff
	clr.l	(a0)
	move.l	d0,a1
	CALLEXEC FreeVec
.no_xbuff
	movem.l	(a7)+,d1-a6
	rts




;--------------------------------------
; exit
ende
	tst	(audioopen,a4)
	beq.b	.noaudio
	lea	($dff000),a5
	move	#$780,d0
	move	d0,(intena,a5)
	moveq	#0,d0
	move	d0,(aud0vol,a5)
	move	d0,(aud1vol,a5)
	move	d0,(aud2vol,a5)
	move	d0,(aud3vol,a5)
	move	#$000f,(dmacon,a5)
	move.l	(4.w),a6
	move.l	(oldlevel4,pc),d0
	beq.b	.noint
	moveq	#7,d0		;INTB_AUD0
	move.l	(oldlevel4,pc),a1
	CALL	SetIntVector
.noint	move.l	(ioreq,pc),a1
	CALL	CloseDevice
.noaudio
	move.l	(mytask,pc),d0
	beq.b	.nopri
	move.l	d0,a1
	move.l	(oldpri,pc),d0
	CALLEXEC SetTaskPri
.nopri
	move.l	(ioreq,pc),d0
	beq.b	.noioreq
	move.l	d0,a0
	CALLEXEC DeleteIORequest
.noioreq
	move.l	(msgport,pc),d0
	beq.b	.nomsgport
	move.l	d0,a0
	CALLEXEC DeleteMsgPort
.nomsgport

	move.l	(signal,pc),d0
	moveq	#-1,d1
	cmp.l	d0,d1
	beq.b	.nosignal
	CALLEXEC FreeSignal
.nosignal
	move.l	(rdargs,pc),d1
	beq.b	.noargs
	CALLDOS	FreeArgs
.noargs

	lea	(smpfh1,pc),a0
	bsr.w	_XClose
	lea	(smpfh2,pc),a0
	bsr.w	_XClose

	move.l	(info_req_window,pc),d0
	beq.b	.noreqwindow
	move.l	d0,a0
	CALLINT	FreeSysRequest
.noreqwindow
	move.l	(g_glist,pc),d7
	beq.b	.nogadgets
	move.l	(intuiwindow,pc),a0
	move.l	d7,a1
	moveq	#-1,d0
	CALLINT	RemoveGList
	move.l	d7,a0
	CALLGT	FreeGadgets
.nogadgets
	move.l	(visualinfo,pc),d0
	beq.b	.novisinfo
	move.l	d0,a0
	CALLGT	FreeVisualInfo
.novisinfo
	move.l	(gadtoolsbase,pc),d0
	beq.b	.nogtlib
	move.l	d0,a1
	CALLEXEC CloseLibrary
.nogtlib
	move.l	(xpkbase,pc),d0
	beq.b	.noxpklib
	move.l	d0,a1
	CALLEXEC CloseLibrary
.noxpklib
	move.l	(utilitybase,pc),d0
	beq.b	.noutillib
	move.l	d0,a1
	CALLEXEC CloseLibrary
.noutillib
	move.l	(iconbase,pc),d0
	beq.b	.noiconlib
	move.l	d0,a1
	CALLEXEC CloseLibrary
.noiconlib
	move.l	(buffspt,pc),d0
	beq.b	.nostereobuff
	move.l	d0,a1
	CALLEXEC FreeVec
.nostereobuff
	move.l	(loadallvec,pc),d0
	beq.b	.notloadall
	move.l	d0,a1
	CALLEXEC FreeVec
.notloadall
	move.l	(oldcurrdir,pc),d1
	beq.b	.nocurrdir
	CALLDOS	CurrentDir
.nocurrdir
	move.l	(intuiwindow,pc),d0
	beq.b	.nowin
	move.l	d0,a0
	CALLINT	CloseWindow
.nowin
	move.l	(pubscreen,pc),d0
	beq.b	.nopubscr
	sub.l	a0,a0
	move.l	d0,a1
	CALLINT	UnlockPubScreen
.nopubscr
	move.l	(conwindow,pc),d7
	beq.b	.nocon
	move.l	d7,d1
	lea	(anykeytxt,pc),a0
	move.l	a0,d2
	CALLDOS	FPutS
	move.l	d7,d1
	CALL	FGetC
	move.l	d7,d1
	CALL	Close
.nocon
	move.l	(wbmsg,pc),d0
	beq.b	.nowbmsg
	move.l	d0,a1
	CALLEXEC ReplyMsg
.nowbmsg
	move.l	(error,pc),d0
	rts
err_ende
	lea	(error+2,pc),a0
	move	#10,(a0)
	bra.w	ende



;--------------------------------------
; data area

dosnam		dc.b	"dos.library",0
gfxnam		dc.b	"graphics.library",0
utilnam		dc.b	"utility.library",0
iconnam		dc.b	"icon.library",0
xpknam		dc.b	"xpkmaster.library",0
rtnam		dc.b	"reqtools.library",0
intuinam	dc.b	"intuition.library",0
gtnam		dc.b	"gadtools.library",0
audionam	dc.b	"audio.device",0
connam		dc.b	"CON://// PSMP output",0
filereqtitle	dc.b	"PSMP: select IFF-8SVX file",0,0
filereqtags	dc.l	0
gadtoolsbase	dc.l	0
dosbase		dc.l	0
gfxbase		dc.l	0
utilitybase	dc.l	0
iconbase	dc.l	0
xpkbase		dc.l	0
intuitionbase	dc.l	0
read_busy	dc	0
is_stereo	dc	0
smpfh1		blk.b	mfh_SIZEOF,0
smpfh2		blk.b	mfh_SIZEOF,0
oldlevel4	dc.l	0
wbmsg		dc.l	0
output		dc.l	0
conwindow	dc.l	0
oldcurrdir	dc.l	0
pubscreen	dc.l	0
intuiwindow	dc.l	0
loadallvec	dc.l	0

tt_rate		dc.b	"PLAYBACKRATE",0
tt_filter	dc.b	"FILTER",0
tt_repeat	dc.b	"REPEAT",0
tt_info		dc.b	"INFO",0
tt_loadall	dc.b	"LOADALL",0
tt_noprogress	dc.b	"NOPROGRESS",0
tt_noinfo	dc.b	"NOINFO",0
tt_pubscreen	dc.b	"PUBSCREEN",0
rdargs		dc.l	0
template	dc.b	"FILE,P=PLAYBACKRATE/K/N,F=FILTER/S,R=REPEAT/S,I=INFO/S,L=LOADALL/S,NP=NOPROGRESS/S,NI=NOINFO/S,PS=PUBSCREEN/K",0
args_start
filenamept	dc.l	0
playbackrate	dc.l	0
filter		dc.l	0
repeat		dc.l	0
info		dc.l	0
loadall		dc.l	0
noprogress	dc.l	0
noinfo		dc.l	0
pubscrnam	dc.l	0
args_end

FILTER_ID="FI"
REPEAT_ID="RE"
INFO_ID="IN"

easystruct_	dc.l	20	;len
		dc.l	0	;flags
		dc.l	0	;title
		dc.l	0	;message
		dc.l	0	;gadgets
info_req_gad	dc.b	"Infect rulez!",0
info_req_msg	dc.b	"%s",10		;version string
		dc.b	"by Smack/Infect",10,10
		dc.b	"file:  '%s'",10
		dc.b	"rate:  %ld Hz",10
		dc.b	"duration:  %d min %02d.%03d sec",0
info_req_args	dc.l	0	;version
		dc.l	0	;filename
		dc.l	0	;sampling rate
		dc	0,0,0	;min,sec,milli
info_req_window	dc.l	0

newgadgettags	dc.l	1<<31+$80000+15,-1	;GA_Immediate = TRUE
newgadgettags_e	dc.l	TAG_DONE
gadget_left	dc.l	0
gadget_right	dc.l	0
newgadget_
ng_left_	dc	0
ng_top_		dc	0
ng_width_	dc	0
ng_height_	dc	0
ng_txt_		dc.l	0	;gadgettext
ng_txtattr_	dc.l	0	;textattr
ng_gid_		dc	0	;gadgetID
ng_flags_	dc.l	0	;flags
ng_visinfo_	dc.l	0	;visualinfo
		dc.l	0	;userdata

gtxt_filter	dc.b	"Filter",0
gtxt_filter_chars=*-gtxt_filter-1
gtxt_repeat	dc.b	"Repeat",0
gtxt_repeat_chars=*-gtxt_repeat-1
gtxt_info	dc.b	"Info",0
gtxt_info_chars=*-gtxt_info-1
		even
g_glist		dc.l	0
g_context	dc.l	0
g_filter	dc.l	0
g_repeat	dc.l	0
g_info		dc.l	0
new_gadget_state	dc.l	0
do_info_req		dc.l	0
idcmp_softint	dc.l	0,0		;is_Node ln_Succ, ln_Pred
		dc.b	2,0		;is_Node ln_Type, ln_Pri
		dc.l	0		;is_Node ln_Name
		dc.l	0,check_idcmp	;is_Data, is_Code

window_title
int_name	dc.b	"PSMP",0,0
int_struct	dc.l	0,0		;is_Node ln_Succ, ln_Pred
		dc.b	2,0		;is_Node ln_Type, ln_Pri
		dc.l	int_name	;is_Node ln_Name
		dc.l	0,mylevel4	;is_Data, is_Code

openwindow_tags
owt_left	dc.l	$80000064,0	;WA_Left
owt_top		dc.l	$80000065,0	;WA_Top
owt_width	dc.l	$80000076,300	;WA_InnerWidth
owt_height	dc.l	$80000077,0	;WA_InnerHeight
		dc.l	$8000006a	;WA_IDCMP:
			;IDCMP_CloseWindow + IDCMP_GadgetDown + IDCMP_GadgetUp
		dc.l	$200+$20+$40
		dc.l	$8000006b	;WA_Flags:
			;ACTIVATE+CLOSEGADGET+DRAGBAR+DEPTHGADET+NOCAREREFRESH+RMBTRAP+SMARTREFRESH+GIMMEZEROZERO
		dc.l	$1000+8+2+4+$20000+$10000+0+$400
		dc.l	$8000006e,window_title;WA_Title
owt_pubscr	dc.l	$80000079,0	;WA_PubScreen
		dc.l	TAG_DONE

packername	dc.b	0,0,0,0,0
xpkerrormsg	ds.b	XPKERRMSGSIZE+1

xpkerrtxtargs
xpk_error	dc.l	0
		dc.l	xpkerrormsg

xpktxt_args
packernamept	dc.l	packername
packerratio	dc.l	0
packerchszKB	dc.l	0

infotxt_args
bodylenKB	dc.l	0
rate		dc.l	0
stereostr	dc.l	0
compression	dc	0
compstr		dc.l	0
rate_arg	dc.l	0
rate_amiga	dc	0
rate_play	dc.l	0
minutes		dc	0
seconds		dc	0
millisec	dc	0

stereostart	dc.l	0
bodystart	dc.l	0
currpos		dc.l	0
bodylen		dc.l	0
bodyend		dc.l	0

error		dc.l	0
buff1pt		dc.l	buff1
buff2pt		dc.l	buff2
buff1size	dc.l	buffersize
buff2size	dc.l	buffersize
buffspt		dc.l	0
buffs1pt	dc.l	0
buffs2pt	dc.l	0
buffs1size	dc.l	buffersize
buffs2size	dc.l	buffersize
lbuffpt		dc.l	lbuff
filenamebuffpt	dc.l	filenam
filepart	dc.l	0
filepartlen	dc.l	0
filepartwidth	dc.l	0
fontheight	dc.l	0
timetxtwidth	dc.l	0
timetxtx	dc.l	0
timetxty	dc.l	0
timemin		dc.l	0
timesec		dc.l	0
pbleft		dc.l	0
pbright		dc.l	0
pbtop		dc.l	0
pbbot		dc.l	0
pbwidth		dc.l	0
pbcurrent	dc.l	0
playedbytes	dc.l	0
bytestoplay	dc.l	0

visualinfo	dc.l	0
oldpri		dc.l	0
mytask		dc.l	0
signal		dc.l	-1
msgport		dc.l	0
ioreq		dc.l	0
channelmap	dc	$0f0f
audioopen	dc	0
oneshot_last	dc	0
firstirq	dc	0
playmode	dc	0	;0=large ( > buffersize*2 )
				;else small ( < buffersize*2 )
initial_value	dc.b	0
initial_value2	dc.b	0


vstr		dc.b	"$VER: PSMP 1.00 (Tue 21-Jan-97)",0
maintxt		dc.b	27,"[1mPSMP 1.00 (Tue 21-Jan-97) by Smack/Infect",27,"[0m",10,0
filetxt		dc.b	" file......%s",10,0
xpktxt		dc.b	" XPK.......%s, %ld%% gain, chunksize %ld KB",10,0
infotxt		dc.b	" features..%ld KB, %ld Hz, %s, compression %d (%s)",10
		dc.b	" rate......%ld Hz -> period %d -> %ld Hz",10
		dc.b	" duration..%d min %02d.%03d sec",10,0
comp0txt	dc.b	"none",0
comp1txt	dc.b	"Fibonacci Delta",0
comp2txt	dc.b	"Exponential Delta",0
monotxt		dc.b	"mono",0
stereotxt	dc.b	"stereo",0
argwarntxt	dc.b	"** wrong arguments, using default.",10,0
audioerrtxt	dc.b	"** can't allocate audio channels.",10,0
readerrtxt	dc.b	"** read error.",10,0
comperrtxt	dc.b	"** unknown compression.",10,0
xpkerrtxt	dc.b	"** XPK error %ld: %s",10,0
xpkliberrtxt	dc.b	"** can't open xpkmaster.library.",10,0
memerrtxt	dc.b	"** not enough memory.",10,0
pubscrtxt	dc.b	"** can't lock public screen '%s'",10,0
anykeytxt	dc.b	10,"press return to continue.",0
timetxt		dc.b	" 00:00 / 00:00 "
timetxtlen=*-timetxt
timetxt_cm=timetxt+1
timetxt_cs=timetxt+1+3
timetxt_tm=timetxt+1+8
timetxt_ts=timetxt+1+11

	section	bbbb,bss_c
buff1	ds.b	buffersize
buff2	ds.b	buffersize


	section	cccc,bss
filenam	ds.b	1024
psnam	ds.b	256
lbuff	ds.b	buffersize
