*SOURCELISTING for Devpac 2.xx, tabsize 8
* BigSamplePlayer: plays huge (raw) samples from harddisk
*
* by GertJan 'Bugs' van Ratingen
*    P. Dijkmansstraat 1c
*    5611 RA  Eindhoven
* on 03-oct-90
* last version 30 okt 90

BUFSIZE		EQU 100*1024		;100kb buffer
VOLUME		EQU 64			;volume
RATE		EQU 20000		;default samplerate
R		EQU RATE/10000*279365	;just some maths
SAMPER		EQU 100000000/R		;

is_code		EQU $12			;offset for int.handler
is_data		EQU $0e			;int.vector
is_size		EQU $16			;size of intvector struct
custom		EQU $DFF000
dmacon		EQU $096
intena		EQU $09A
intreq		EQU $09C
DMAF_SETCLR	EQU $8000
DMAF_AUD0	EQU $0001
DMAF_AUD1	EQU $0002
INTF_SETCLR	EQU (1<<15)
INTF_AUD1	EQU (1<<8)
INTF_AUD0	EQU (1<<7)
INTB_AUD1	EQU (8)
INTB_AUD0	EQU (7)

MEMF_CHIP	EQU 2
MEMF_PUBLIC	EQU 1
FIRE		EQU $BFE001

****************************************
* register useage:
*
* d0..d3 = buffers; parameters for librarycalls
*     d4 = startaddress buffer 1
*     d5 = startaddress buffer 2
*     d6 = dosbase
*     d7 = last arg found; bytes read from file
*
*     a2 = startaddress argument; start custom chips
*     a3 = endaddress argument; sampleperiod
*     a4 = inputfilehandle
*     a5 = startaddress buffer 1; sounddone
*     a6 = library base
*     a7 = stackpointer
****************************************

start:
*------------------------------------------------------------------------*
* open dos library
*------------------------------------------------------------------------*
	movem.l	d0/a0,-(sp)
	movea.l	$4,a6
	lea	dosname(pc),a1
	jsr	-408(a6)		;oldopenlibrary()
	move.l	d0,d6			;dosbase
	movem.l	(sp)+,d0/a0
	tst.l	d6
	beq	tocli

*------------------------------------------------------------------------*
* get filename from command line, or stick to default name "sample"
*------------------------------------------------------------------------*
	subq.l	#1,d0
	beq	noarg
	move.b	#0,(a0,d0)		;erase linefeed-character
	moveq	#1,d7
	bsr	getarg
	beq	noarg
	movea.l	a0,a3
	cmp.b	#'?',(a2)
	beq	printhelp
	bra	openfile
noarg:
	lea	samplename(pc),a2
	lea	sampleend(pc),a3
	moveq	#0,d7			;no args left
openfile:
	bsr	printad
	move.l	a2,d1
	move.l	#1005,d2		;accesmode mode_old
	movea.l	d6,a6			;dosbase
	jsr	-30(a6)			;open()
	move.l	d0,a4			;filehandle
	beq	nofile

	lea	fopentxt(pc),a0
	moveq	#fopenlen,d3
	bsr	printa0

*------------------------------------------------------------------------*
* open two buffers in chipmem
*------------------------------------------------------------------------*
openbuf:
	movea.l	$4,a6
	move.l	#BUFSIZE,d0
	move.l	#MEMF_CHIP+MEMF_PUBLIC,d1
	jsr	-198(a6)		;allocmem()
	move.l	d0,d4			;buf1
	beq	nomemory

	move.l	#BUFSIZE,d0
	move.l	#MEMF_CHIP+MEMF_PUBLIC,d1
	jsr	-198(a6)		;allocmem()
	move.l	d0,d5
	beq	nomemory

	lea	memtxt(pc),a0
	moveq	#memlen,d3
	bsr	printa0

*------------------------------------------------------------------------*
* examine command line for optional speed
*------------------------------------------------------------------------*
	lea	1(a3),a0
	moveq	#0,d1
	bsr	getarg
	beq	speed

*------------------------------------------------------------------------*
* convert argument to number
*------------------------------------------------------------------------*
	moveq	#0,d1
opt:	move.b	(a2)+,d0
	beq	speed
	subi.b	#$30,d0
	bmi	opt			;skip if digit < 0
	cmpi.b	#9,d0			;digit > 9 ?
	bhi	opt			;then skip
	mulu	#10,d1
	add.b	d0,d1
	bra	opt

*------------------------------------------------------------------------*
* read data from file to buffer1
*------------------------------------------------------------------------*
speed	move.l	d1,a3

	bsr	read4			;read first 4 bytes
	beq	done
	move.l	d4,a5
	cmp.l	#"FORM",(a5)
	bne	readraw
*------------------------------------------------------------------------*
* it seems to be an IFF file; a closer look could be useful
*------------------------------------------------------------------------*
	bsr	read4			;skip formsize
	bsr	read4			;read next chunk-ID
	cmp.l	#"8SVX",(a5)		;is it a 8SVX-chunk?
	bne	readraw			;no, treat it as a raw file...
	lea	ifftxt(pc),a0
	moveq	#ifflen,d3
	bsr	printa0
check:	bsr	read4			;read next chunk-ID
	beq	done
	cmp.l	#"BODY",(a5)
	beq	readnext

vhdr:	cmp.l	#"VHDR",(a5)
	bne	name
	bsr	read4			;get vhdr size
	move.l	d4,d2
	move.l	(a5),d3
	bsr	readit			;read vhdr
	beq	done
	lea	ratenum(pc),a0
	moveq	#4,d0
clrloop:
	move.b	#' ',(a0)+
	dbra	d0,clrloop
	move.w	12(a5),d0		;samplerate
	bsr	i2d			;convert rate to string
	move.w	12(a5),d0		;samplerate
*------------------------------------------------------------------------*
* lets calculate the period ( = 3579546.471462/rate)
*------------------------------------------------------------------------*
	move.w	#65082,d1		;3579546/55 = 65082
	divu	d0,d1			;d1.w = quotient
	move.l	d1,d2
	swap	d2			;d2.w = remainder
	mulu	#55,d1			; do some more maths
	mulu	#55,d2			; to get as close
	move.w	d0,d3			; as possible to the
	asr.w	#1,d3			; period
	add.w	d3,d2
	divu	d0,d2
	add.w	d2,d1			;d1.w = period

	move.l	a3,d0			;check if a3 is empty
	bne	printrate
	move.w	d1,a3			;adjust period
printrate:
	lea	pernum(pc),a0
	moveq	#3,d0
clrloop2:
	move.b	#' ',(a0)+
	dbra	d0,clrloop2
	move.l	d1,d0
	bsr	i2d			;convert period to string
	lea	ratetxt(pc),a0
	moveq	#ratelen,d3
	bsr	printa0
*------------------------------------------------------------------------*
* print comment-chunks
*------------------------------------------------------------------------*
name:	cmp.l	#"NAME",(a5)
	bne	auth
	lea	nametxt(pc),a0
	bra	prfrmtxt
auth:	cmp.l	#"AUTH",(a5)
	bne	anno
	lea	authtxt(pc),a0
	bra	prfrmtxt
anno:	cmp.l	#"ANNO",(a5)
	bne	copyr
	lea	annotxt(pc),a0
	bra	prfrmtxt
copyr:	cmp.l	#"(C) ",(a5)
	bne	check
	lea	copytxt(pc),a0
prfrmtxt:
	moveq	#copylen,d3
	bsr	printa0
	bsr	formtext
	bra	check

*------------------------------------------------------------------------*
* fill first buffer with (raw) data
*------------------------------------------------------------------------*
readraw:
	move.l	d4,d2			;buffer
	addq.l	#4,d2
	move.l	#BUFSIZE,d3		;length
	subq.l	#4,d3
	bsr	readit
	addq.l	#4,d7			;correct # bytes read
	bra	filled1
readnext:
	bsr	readfile
filled1:
	lea	ifftxt(pc),a0
	moveq	#1,d3			;only the linefeed
	bsr	printa0
	move.b	#'1',d2
	bsr	printread

*------------------------------------------------------------------------*
* set interrupt-vector for audio channel 0
*------------------------------------------------------------------------*
	lea	AUD0Interrupt(pc),a1
	lea	flags(pc),a0
	move.l	a0,is_data(a1)
	lea	AUD0Handler(pc),a0
	move.l	a0,is_code(a1)
	moveq	#INTB_AUD0,d0
	movea.l	$4,a6
	jsr	-162(a6)		;SetIntVector

*------------------------------------------------------------------------*
* initialise soundchannels 0 and 1
*------------------------------------------------------------------------*
	move.l	a3,d0
	bne	setcustom
	move.w	#SAMPER,a3		;default
setcustom:
	lea	custom,a2		;base for custom chips
	move.l	d4,d0
	bsr	setdata
	move.w	#VOLUME,$a8(a2)		;volume for channel 0
	move.w	a3,$a6(a2)		;sample period for 0
	move.w	#VOLUME,$b8(a2)		;volume for channel 1
	move.w	a3,$b6(a2)		;sample period for 1
	move.w	#DMAF_AUD0|DMAF_AUD1,dmacon(a2)
	move.w	#INTF_AUD0,intena(a2)

	move.w	#1000,d1
WaitDMA:
	dbra	d1,WaitDMA		;seems to be neccesary...

*------------------------------------------------------------------------*
* let's play buffer1
*------------------------------------------------------------------------*
	move.w	#INTF_AUD0,intreq(a2)
	move.w	#INTF_SETCLR|INTF_AUD0,intena(a2)
	move.w	#DMAF_SETCLR|DMAF_AUD0|DMAF_AUD1,dmacon(a2)

last1:	bsr	printplay

	lea	sounddone(pc),a5
	move.b	#0,(a5)			;reset play-flag

*------------------------------------------------------------------------*
* if buffer1 contains last part of file, goto endplay
*------------------------------------------------------------------------*
	cmpi.l	#BUFSIZE,d7
	bne	endplay

*------------------------------------------------------------------------*
* read data from file to buffer2
*------------------------------------------------------------------------*
	move.l	d5,d2			;buffer
	bsr	readfile

	move.b	#'2',d2
	bsr	printread

*------------------------------------------------------------------------*
* set start and size for buffer 2, while buffer 1 is being played
*------------------------------------------------------------------------*
	move.l	d5,d0
	bsr	setdata

*------------------------------------------------------------------------*
* wait for interrupt when buffer1 is done
*------------------------------------------------------------------------*
wait1:	btst	#6,FIRE			;mousebutton?
	beq	stopplay		;then quit
	tst.b	(a5)			;sound played?
	beq	wait1			;no
	move.b	#0,(a5)			;reset play-flag

*------------------------------------------------------------------------*
* buffer2 starts playing now
*------------------------------------------------------------------------*
	bsr	printplay

*------------------------------------------------------------------------*
* if buffer2 contains last part of file, goto endplay
*------------------------------------------------------------------------*
	cmpi.l	#BUFSIZE,d7
	bne	endplay

*------------------------------------------------------------------------*
* read data from file to buffer1
*------------------------------------------------------------------------*
	move.l	d4,d2			;buffer
	bsr	readfile

	move.b	#'1',d2
	bsr	printread

*------------------------------------------------------------------------*
* set start and size for buffer 1, while buffer 2 is being played
*------------------------------------------------------------------------*
	move.l	d4,d0
	bsr	setdata

*------------------------------------------------------------------------*
* wait for interrupt when buffer2 is done
*------------------------------------------------------------------------*
wait2:	btst	#6,FIRE			;mousebutton?
	beq	stopplay		;then quit
	tst.b	(a5)			;sound played?
	beq	wait2			;no
	move.b	#0,(a5)			;reset play-flag

*------------------------------------------------------------------------*
* buffer1 starts playing now
*------------------------------------------------------------------------*
	bra	last1

*------------------------------------------------------------------------*
* wait for interrupt to finish last buffer, close soundchannels
*------------------------------------------------------------------------*
endplay:
waitend:
	btst	#6,FIRE			;mousebutton?
	beq	stopplay		;then quit
	tst.b	(a5)			;sound played?
	beq	waitend			;no
stopplay:
	move.w	#DMAF_AUD0|DMAF_AUD1,dmacon(a2)
	move.w	#INTF_AUD0,intena(a2)
	move.w	#INTF_AUD0,intreq(a2)
	move.w	#0,$a8(a2)		;volume off
	move.w	#0,$b8(a2)		;volume off

done:	lea	endtxt(pc),a0
	moveq	#endlen,d3
	bsr	printa0

*------------------------------------------------------------------------*
* this is almost the end of this program, let's clean up used resources
*------------------------------------------------------------------------*
freebuf2:
	movea.l	$4,a6
	movea.l	d5,a1
	move.l	#BUFSIZE,d0
	jsr	-210(a6)		;freemem()
freebuf1:
	movea.l	$4,a6
	movea.l	d4,a1
	move.l	#BUFSIZE,d0
	jsr	-210(a6)		;freemem()
closefile:
	movea.l	d6,a6
	move.l	a4,d1
	jsr	-36(a6)			;close()
exit:
	movea.l	$4,a6
	movea.l	d6,a1
	jsr	-414(a6)		;closelibrary()
tocli:
	moveq	#0,d0
	rts

*------------------------------------------------------------------------*
*						SUBROUTINES
*------------------------------------------------------------------------*
printhelp:
	lea	helptxt(pc),a0
	move.l	#helplen,d3
	bra	dolast
nofile:
	lea	nofiletxt(pc),a0
	moveq	#nofilelen,d3
	bsr	printa0
	movea.l	a2,a0
	move.l	a3,d3
	sub.l	a2,d3
	bsr	printa0
	lea	nofitxt2(pc),a0
	moveq	#nofilen2,d3
dolast:	bsr	printa0
	bra	exit
nomemory:
	lea	nomemtxt(pc),a0
	move.l	#nomemlen,d3
	bsr	printa0
	tst.l	d4
	beq	closefile
	bra	freebuf1

printad:
	lea	adtxt(pc),a0
	moveq	#adlen,d3
	bra	printa0
printread:
	lea	readtxt(pc),a0
	move.b	d2,7(a0)		;"1" or "2"
	moveq	#readlen,d3
	bra	printa0
printplay:
	lea	playtxt(pc),a0
	moveq	#playlen,d3
printa0:
	exg	d2,a0
print:
	movea.l	d6,a6
	jsr	-60(a6)			;output()
	exg	d0,d1
	jmp	-48(a6)			;write()


setdata:
	move.l	d0,$a0(a2)		;start audiodata
	move.l	d0,$b0(a2)
	move.l	d7,d0
	asr.l	#1,d0			;length/2
	move.w	d0,$a4(a2)		;length of data
	move.w	d0,$b4(a2)
	rts

read4:
	move.l	d4,d2
	moveq	#4,d3
	bra	readit
readfile:
	move.l	#BUFSIZE,d3		;length
readit:
	movea.l	d6,a6
	move.l	a4,d1			;file
	jsr	-42(a6)			;read()
	move.l	d0,d7
	rts

formtext:
	bsr	read4			;get chunksize
	beq	ftexit
	move.l	(a5),d3			;chunksize
	move.l	d4,d2			;load to buffer1
	bsr	readit			;read chunk
	beq	ftexit
	move.b	#10,(a5,d3.w)		;add linefeed
	addq.l	#1,d3			;line contains one more char
	bra	print			;and print the line
ftexit:	rts

*------------------------------------------------------------------------*
* convert integer in d0 to string (a0 points to end of string)
*------------------------------------------------------------------------*
i2d:	divu	#10,d0
	swap	d0
	addi.w	#'0',d0
	move.b	d0,-(a0)
	clr.w	d0
	swap	d0
	cmp.w	#0,d0
	bne	i2d
	rts

AUD0Handler:				;Aud0Interrupt-Handler
	lea	sounddone(pc),a0
	move.b	#1,(a0)
	lea	custom,a0
	move.w	#INTF_AUD0,intreq(a0)
	rts

**************************************************************************
* get next argument from CLI-command
**************************************************************************
getarg:	bclr	#0,d0			;quotes off
	tst.b	d7
	beq	argend
nospace:
	tst.b	(a0)
	beq	argend
	cmpi.b	#' ',(a0)+
	beq	nospace
	subq.l	#1,a0
noopt:	cmpi.b	#'"',(a0)		;quotes around filename?
	bne	argchar
	bset	#0,d0			;yes
	addq.l	#1,a0
argchar:
	movea.l	a0,a2			;argstart
argchar1:
	tst.b	(a0)			;NULL?
	beq	argsfound
	cmp.b	#' ',(a0)		;space?
	bne	nxtchar
	btst	#0,d0			;inside quotes?
	beq	argfound		;no
nxtchar:
	cmp.b	#'"',(a0)
	bne	nxtchar2
	btst	#0,d0			;inside quotes?
	bne	argfound		;yep
nxtchar2:
	addq.l	#1,a0
	bra	argchar1
argsfound:
	moveq	#0,d7
argfound:
	move.b	#0,(a0)			;close filename with NULL
	cmpa.l	a2,a0			;argstart
argend:	rts

*------------------------------------------------------------------------*
* some variables
*------------------------------------------------------------------------*
AUD0Interrupt:	ds.b	is_size

flags:		dc.w	0		;interruptflags (not used)
sounddone:	dc.b	0		;0 = sound is playing
					;1 = soundplay ready

*------------------------------------------------------------------------*
* the strings and messages BIG can't do without....
*------------------------------------------------------------------------*

dosname:	dc.b 'dos.library',0
samplename:	dc.b 'sample',0
sampleend	EQU	*-1
helptxt:	dc.b 10
		dc.b 'Usage: BIG [samplename [period]]',10,10
adtxt:		dc.b $9b,'41;30m  BIGSAMPLEPLAYER  ',$9b,'0m'
adlen		EQU	*-adtxt
	dc.b $9b,'1m  © 1990  GJ van Ratingen',$9b,'0m',10,10
	dc.b 11,'plays huge samples (raw or 8SVX format) from harddisk.',10,10
	dc.b 'Default filename: "sample"',10
	dc.b 'Default period: taken from 8SVX-file; 179 in other cases.',10
helplen		EQU	*-helptxt
nofiletxt:	dc.b 10,10,"I can't find ",'"'
nofilelen	EQU	*-nofiletxt
nofitxt2:	dc.b '"',10
nofilen2	EQU	*-nofitxt2

nomemtxt:	dc.b 'No buffer memory!',10
nomemlen	EQU	*-nomemtxt
fopentxt:	dc.b 10,'File opened. '
fopenlen	EQU	*-fopentxt
memtxt:		dc.b 'Memory OK. Hold left mousebutton to stop.',10
memlen		EQU	*-memtxt
readtxt:	dc.b 'Buffer x filled',10
readlen		EQU	*-readtxt
playtxt:	dc.b 11,9,' playing',10
playlen		EQU	*-playtxt
endtxt:		dc.b 'All done.',10
endlen		EQU	*-endtxt
ifftxt:		dc.b 10,'IFF-8SVX header found!',10
ifflen		EQU	*-ifftxt
nametxt:	dc.b 'Samplename: '
namelen		EQU	*-nametxt
authtxt:	dc.b 'Author    : '
authlen		EQU	*-authtxt
annotxt:	dc.b 'Remark    : '
annolen		EQU	*-annotxt
copytxt:	dc.b 'Copyright : '
copylen		EQU	*-copytxt
ratetxt:	dc.b 'Samplerate: '
ratenum:	dc.b '      bytes/sec',10
		dc.b 'Period    : '
pernum:		dc.b '     ',10
ratelen		EQU	*-ratetxt

