; PlayIt veneers
; by Rick Hudson, (c) 1999
; assembles with asm
; this source uses AOF register bindings for sl,fp,ip,sp,lr,pc (ie R10-R15)
; but plain ol' r0-r9 for the rest since the SWIs are defined in terms of them
; and it's confusing when arranging registers to sometimes use r0-r3 and sometimes
; a1-a4. So it is avoided.
;
; all 'out' parameters (ie those for writing return values) are tested and only
; written if they are non-NULL
;
; If the SWI returns an error return is immediate with any return parameters
; undefined (specifically they are not changed).
;
; PlayIt needs to be loaded to assemble this for SWI name lookup


; macro for returning a parameter (currently in register preg) for which the address of
; the location to store it is on the stack 'stack' words from sp (ie at sp+4*stack).

		MACRO	RETPARS,preg,stack
		ldr	lr,[sp,#stack*4]
		teq	lr,#0
		strne	preg,[lr]
		ENDM

; macro for returning a parameter (currently in register preg) for which the address of
; the location to store it is in areg.

		MACRO	RETPARR,preg,areg
		teq	areg,#0
		strne	preg,[areg]
		ENDM

		AREA	ASM$$Code,Code,Readonly


; playit_error *xplayit_version(/*out*/int *version)

		export	xplayit_version
xplayit_version:
		mov	ip,lr		; keep lr somewhere safe
		mov	r3,r0		; move return parameter out of the way
		swi	"XPlayIt_Version"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r3		; if (r3) [r3]=r0
		mov	a1,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_config_bits(/*in*/playit_configbits clear, playit_configbits xor,
;                                   /*out*/playit_configbits *newflags, playit_configbits *oldflags)

		export	xplayit_config_bits
xplayit_config_bits:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r2}	; move 1st return parameter out of the way
		mov	r2,r1		; set up parameters...
		mov	r1,r0		; ... for call to SWI
		mov	r0,#0		; reason = 0
		swi	"XPlayIt_Config"
		addvs	sp,sp,#4	; if error, purge stack...
		movvss	pc,ip		; ...and return
		ldmfd	sp!,{lr}	; fetch 1st return par off stack
		RETPARR	r1,lr		; if (lr) [lr]=r1
		RETPARR	r2,r3		; if (r3) [r3]=r2
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_config_discbuffer(/*in*/int size, /*out*/int *oldsize)

		export 	xplayit_config_discbuffer
xplayit_config_discbuffer:
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r1		; move return parameter out of the way
		mov	r1,r0		; set up registers for SWI
		mov	r0,#1		; reason = 1
		swi	"XPlayIt_Config"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r1,r2		; if (r2) [r2]=r1
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_config_echodelay(/*in*/int ms, /*out*/int *oldms)

		export	xplayit_config_echodelay
xplayit_config_echodelay:
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r1		; move return parameter out of the way
		mov	r1,r0		; set up registers for SWI
		mov	r0,#2		; reason = 2
		swi	"XPlayIt_Config"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r1,r2		; if (r2) [r2]=r1
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_config_killbuffer(void)

		export 	xplayit_config_killbuffer
xplayit_config_killbuffer:
		mov	ip,lr		; keep lr somewhere safe
		mov	r0,#3		; reason = 3
		swi	"XPlayIt_Config"
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_load_driver(/*in*/const char *name)

		export	xplayit_load_driver
xplayit_load_driver:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_LoadDriver"
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_driver_info(/*out*/char **name, char **descr,
;                         char **version, int *framerate, int *mode)

		export	xplayit_driver_info
xplayit_driver_info:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r0-r3}	; all 5 parameters now on stack
		stmfd	sp!,{r4}	; have to preserve this
		swi	"XPlayIt_DriverInfo"
		bvs	xplayit_driver_info_X
		RETPARS	r0,1		; return 1st par if required
		RETPARS	r1,2		; return 2nd par if required
		RETPARS	r2,3		; return 3rd par if required
		RETPARS	r3,4		; return 4th par if required
		RETPARS	r4,5		; return 5th par if required
xplayit_driver_info_X:
		ldmfd	sp!,{r4}
		add	sp,sp,#4*4	; purge parameters from stack
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_sample_info(char **name, playit_format *format,
;              int *framerate, int *bstart, int *bend, int *numframes)

		export	xplayit_sample_info
xplayit_sample_info:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r0-r3}     ; stick all parameters on stack
		stmfd	sp!,{r4-r5}	; store these cos we corrupt them
		swi	"XPlayIt_SampleInfo"
		bvs	xplayit_sample_info_x
		RETPARS	r0,2		; return 1st par if required
		RETPARS	r1,3		; return 2nd par if required
		RETPARS	r2,4		; return 3rd par if required
		RETPARS	r3,5		; return 4th par if required
		RETPARS	r4,6		; return 5th par if required
		RETPARS	r5,7		; return 6th par if required
xplayit_sample_info_x:
		ldmfd	sp!,{r4-r5}	; restore r4 and r5
		add	sp,sp,#4*4	; purge rest of stack
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_status(playit_statusbits *status, playit_frame *frame)

		export	xplayit_status
xplayit_status:
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r0		; keep 1st return in r2
		mov	r3,r1		; keep 2nd return in r3
		swi	"XPlayIt_Status"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r2		; if (r2) [r2]=r0
		RETPARR	r1,r3		; if (r3) [r3]=r1
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_volume(int volume, int *oldvol)

		export	xplayit_volume
xplayit_volume:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_Volume"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r1		; if (r1) [r1]=r0
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_open(const char *filename, playit_format format,
;                       int framerate, int bstart, int bend, int auxpar);

		export	xplayit_open
xplayit_open:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r4-r5}
		add	lr,sp,#2*4	; point lr at original stack
		ldmia	lr,{r4-r5}	; get last two pars off stack
		swi	"XPlayIt_Open"
		ldmfd	sp!,{r4-r5}	; restore original r4,r5
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_open_block(playit_open_block *block)

		export	xplayit_open_block
xplayit_open_block:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r0,r4-r5}
		ldmia	r0,{r0-r5}	; load parameters from block
		swi	"XPlayIt_Open"
		ldmfd	sp!,{lr}	; get back paramater (ptr to block)
		stmia	lr,{r0-r5}	; write registers back to block
		ldmfd	sp!,{r4-r5}	; restore original r4,r5
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_open_autodetect(const char *filename)

		export	xplayit_open_autodetect
xplayit_open_autodetect:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r4-r5}	; save r4,r5 cos swi corrupts them
		mov	r1,#0		; force auto-detect mode
		swi	"XPlayIt_Open"
		ldmfd	sp!,{r4-r5}	; get back r4, r5
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_begin_end(playit_frame start, playit_frame end,
;                           playit_frame *rstart, playit_frame *rend);

		export	xplayit_begin_end
xplayit_begin_end:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_BeginEnd"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r2		; if (r2) [r2]=r0
		RETPARR	r1,r3		; if (r3) [r3]=r1
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_set_ptr(playit_frame frame, playit_frame *rframe)

		export	xplayit_set_ptr
xplayit_set_ptr:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_SetPtr"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r1		; if (r1) [r1]=r0
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_play(void)

		export	xplayit_play
xplayit_play:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_Play"
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_stop(void);

		export	xplayit_stop
xplayit_stop:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_Stop"
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_pause(void);

		export	xplayit_pause
xplayit_pause:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_Pause"
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_balance(int balance, int *rbalance)

		export	xplayit_balance
xplayit_balance:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_Balance"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r1		; if (r1) [r1]=r0
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_pause_at(playit_frame frame, playit_frame *rframe)

		export	xplayit_pause_at
xplayit_pause_at:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_PauseAt"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r1		; if (r1) [r1]=r0
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_vu(int *left, int *right)

		export	xplayit_vu
xplayit_vu:
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r0
		mov	r3,r1
		swi	"XPlayIt_VU"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r2		; if (r2) [r2]=r0
		RETPARR	r1,r3		; if (r3) [r3]=r1
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_list_drivers(int reason, char *dir, void *buffer, int idx, int buffsize,
;                                          int *num_read, int *idx_out);

		export	xplayit_list_drivers
xplayit_list_drivers:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r4-r5}
		mov	r4,r3
		ldr	r5,[sp,#2*4]
		swi	"XPlayIt_ListDrivers"
		bvs	xplayit_list_drivers_X
		RETPARS	r3,3
		RETPARS	r4,4
xplayit_list_drivers_X:
		ldmfd	sp!,{r4-r5}
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_identify(const char *filename, playit_format *format, int *framerate,
;                                      int *bstart, int *bend, int *auxpar, int *numframes)

		export	xplayit_identify
xplayit_identify:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r1-r3}	; all 6 return parameters now on stack
		stmfd	sp!,{r4-r6}	;
		swi	"XPlayIt_Identify"
		bvs	xplayit_identify_X
		RETPARR	r1,3
		RETPARR	r2,4
		RETPARR	r3,5
		RETPARR	r4,6
		RETPARR	r5,7
		RETPARR	r6,8
xplayit_identify_X:
		ldmfd	sp!,{r4-r6}
		add	sp,sp,#3*4	; purge parameters
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_queue_add(const char *filename)

		export	xplayit_queue_add
xplayit_queue_add:
		mov	ip,lr		; keep lr somewhere safe
		mov	r1,r0
		mov	r0,#0		; reason code=0
		swi	"XPlayIt_Queue"
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_queue_flush(void)

		export	xplayit_queue_flush
xplayit_queue_flush:
		mov	ip,lr		; keep lr somewhere safe
		mov	r0,#1		; reason code=1
		swi	"XPlayIt_Queue"
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_set_loop(playit_frame start, playit_frame stop, int count,
;                                      playit_frame *rstart, playit_frame *rstop)

		export	xplayit_set_loop
xplayit_set_loop:
		mov	ip,lr		; keep lr somewhere safe
		swi	"XPlayIt_SetLoop"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r3		; if (r3) [r3]=r0
		RETPARS	r1,0		; if (par5) (*par5)=r1
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_file_info_format(char *filename, playit_sample_info *block)

		export	xplayit_file_info_format
xplayit_file_info_format:
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r1
		mov	r1,r0		; shuffle registers as required
		mov	r0,#0		; reason code=0
		swi	"XPlayIt_FileInfo"
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_file_info_text(/*in*/char *filename, playit_text *block,
;                        int blocksize, playit_text_bits flags, /*out*/ int *nbytes);

		export	xplayit_file_info_text
xplayit_file_info_text:
		mov	ip,lr		; keep lr somewhere safe
		stmfd	sp!,{r4}
		mov	r4,r3
		mov	r3,r2
		mov	r2,r1
		mov	r1,r0		; shuffle registers around
		mov	r0,#1		; reason code=1
		swi	"XPlayIt_FileInfo"
		bvs	xplayit_file_info_text_X
		RETPARS	r3,1		; if (par5) (*par5)=r3
xplayit_file_info_text_X:
		ldmfd	sp!,{r4}
		movvc	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_file_info_filename(char **filename)

		export	xplayit_file_info_filename
xplayit_file_info_filename:
		mov	ip,lr		; keep lr somewhere safe
		mov	r2,r0
		mov	r0,#2		; reason code=2
		swi	"XPlayIt_FileInfo"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r0,r2		; if (r2) [r2]=r0
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_clientop_register(/*in*/int flags, playit_eventbits events,
;                     /*out*/int **pollword)

		export	xplayit_clientop_register
xplayit_clientop_register:
		mov	ip,lr
		mov	r3,r2		; keep this where we can get it later
		mov	r2,r1
		mov	r1,r0
		mov	r0,#0
		swi	"XPlayIt_ClientOp"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r2,r3		; if (r3) [r3]=r2
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return


; playit_error *xplayit_clientop_deregister(/*in*/int *pollword, /*out*/int *num_registered)

		export	xplayit_clientop_deregister
xplayit_clientop_deregister:
		mov 	ip,lr
		mov	r3,r1		; keep return par in r3 for a bit
		mov	r2,r0		; move pollword to r2
		mov	r0,#1
		swi	"XPlayIt_ClientOp"
		movvss	pc,ip		; immediate exit if error
		RETPARR	r1,r3		; if (r3) [r3]=r1
		mov	r0,#0		; set a1=0 for no error
		movs	pc,ip		; return
