

; ----------------------------------- 8 bit sound support ---------------------------------------


	FUNC	ConfigureSound
	STMFD R13!,{R4,R14}
	MOV R12,R0
	LDMIA R12,{R0-R4}
	SWI XSound_Configure
	STMIA R12,{R0-R4}
	LDMFD R13!,{R4,PC}^


	FUNC	SetStereoPosition
	ADD R0,R0,#1
	TEQ R1,#128
	MOVEQ R1,#127
	SWI XSound_Stereo
	MOV R0,R1
	MOVS PC,R14


	FUNC	SoundLog
	SWI XSound_SoundLog
	MOVS PC,R14


	FUNC	SoundControl		; R0=Channel (0..7)
					; R1=Volume (0..15, lin)
					; R2=Pan (-255..255)
	MOV R3,R1
	ADD R0,R0,#1
	MOVS R1,R2
	RSBMIS R1,R1,#0			; R1=0..255 (left..right)
	MOVEQ R1,#1			; R1=1..255
	SUB R1,R1,#128			; R1=-127..127
	SWI XSound_Stereo
	ADR R1,SC_voltable
	LDR R1,[R1,R3,LSL#2]		; Get log volume + gate bits
	MOV R2,#&8000
	MOV R3,#255
	SWI XSound_Control
	MOVS PC,R14

SC_voltable	DCD &180,&1C0,&1D0,&1DA,&1E0,&1E6,&1EA,&1ED
		DCD &1F0,&1F3,&1F6,&1F8,&1FA,&1FC,&1FD,&1FF


	FUNC	InstallVoice
	ADR R0,VoiceBase
	MOV R1,#0			; Get a free slot
	SWI XSound_InstallVoice
	TEQ R1,#0
	MOVEQS PC,R14
	STR R1,VoiceNumber
	MOV R2,#NUM_CHANNELS
	MOV R3,R1
	ADR R12,V_Previous
IV_Attach
	 MOV R0,R2
	 MOV R1,R3
	 SWI XSound_AttachVoice
	 STR R1,[R12],#4
	 SUBS R2,R2,#1
	BGT IV_Attach
	MOV R0,#0
	MOVS PC,R14

VoiceNumber	DCD 0
V_Previous	DCD 0,0,0,0,0,0,0,0


	FUNC	RemoveVoice
	MOV R2,#NUM_CHANNELS
	ADR R12,V_Previous
RV_Attach
	 MOV R0,R2
	 LDR R1,[R12],#4
	 SWI XSound_AttachVoice
	 SUBS R2,R2,#1
	BGT RV_Attach
	LDR R1,VoiceNumber
	SWI XSound_RemoveVoice
	TEQ R1,#0
	MOVNE R0,#0
	MOVS PC,R14


VoiceBase
	B	V_Fill
	B	V_Update
	B	V_GateOn
	B	V_GateOff
	LDMFD	R13!,{PC}		; Instantiate
	LDMFD	R13!,{PC}		; Free
	LDMFD	R13!,{PC}		; Initialise
	DCD	VoiceName-VoiceBase
VoiceName
	=	"DOOM",0
	ALIGN	4


V_GateOn
V_Fill
V_Update
	; R6	Negative if config changed
	; R7	Channel number
	; R8	Sample period
	; R9	->SCCB
	; R10	->End of buffer
	; R11	Buffer increment
	; R12	->Buffer
	; R13	->Return address
	LDR R0,Sound_ready
	LDR R0,[R0]			; Dereference
	CMP R0,#0
	BEQ V_emptyloop
	LDRB R6,[R9,#0]			; R6=Volume+gate bit
	LDR R9,Sound_chan
	LDR R0,[R9,R7,LSL#(3+2)]!	; R0->base of sample (or 0)
					; R9->Channel data
	TEQ R0,#0
	BEQ V_emptyloop
	ANDS R6,R6,#127			; R6=log amplitude
	BEQ V_GateOff			; if 0, turn off
	RSB R6,R6,#127
	LDR R1,[R9,#4]			; R1= Length (make these one block after fiddling)
	LDR R2,[R9,#16]			; R2= pitch	(16.16)
	LDR R3,[R9,#20]			; R3= phase acc (16.16)
	LDR R4,Sound_logtab		; R4->LinToLog
V_fillloop
	 ADD R3,R3,R2
	 CMP R3,R1,LSL#16
	 BHS V_GateOff
	 LDRB R5,[R0,R3,LSR#16]		; R5=sample (8bit unsigned)
	 LDRB R5,[R4,R5]		; Table is for 8 bit unsigned lin
	 SUBS R5,R5,R6,LSL#1		; Attenuate
	 MOVMI R5,#0
	 STRB R5,[R12],R11
	 CMP R12,R10
	BLT V_fillloop
	STR R3,[R9,#20]			; Update phase
	MOV R0,#8			; Active
	LDMFD R13!,{PC}
V_GateOff
	MOV R0,#0
	STR R0,[R9,#0]			; Turn off channel
V_emptyloop
	 CMP R12,R10
	 STRLTB R0,[R12],R11
	BLT V_emptyloop
	MOV R0,#2			; Inactive, clear one more buffer
	LDMFD R13!,{PC}

; ------------------- Shared

		IMPORT	sound_ready
		IMPORT	chan
		IMPORT	LinToLogTable
Sound_ready	DCD	sound_ready	; int
Sound_chan	DCD	chan		; chan_info (NUM_CHANNELS blocks of 8 words)
Sound_logtab	DCD	LinToLogTable	; unsigned char *

; ----------------------------------- 16 bit sound support ---------------------------------------


	FUNC	Sound16_Available
	MOV R0,#0
	SWI XSound_Mode
	MOVVS R0,#0
	MOVS PC,R14


	FUNC	Sound16_SetRate
	MOV R3,R0			; R3=Frequency
	MOV R0,#0
	SWI XSound_SampleRate		; R1=NSR
	MOV R12,R1
	MOV R1,#0
S16SRloop
	 MOV R0,#2
	 SWI XSound_SampleRate		; R2=Rate(R1)
	 CMP R2,R3
	 BGE S16SRfound
	 ADD R1,R1,#1
	 CMP R1,R12
	BLT S16SRloop
	SUB R1,R1,#1			; No rate is high enough, use highest
S16SRfound
	MOV R0,#3
	SWI XSound_SampleRate		; Select rate
	MOV R0,R2			; Return previous rate
	MOVS PC,R14


	FUNC	Sound16_InstallHandler
	ADR R1,LinearHandler
	MOV R2,#0
	MOV R0,#1
	SWI XSound_LinearHandler
	STR R1,S16Hprevhandler
	STR R2,S16Hprevhandler+4
	MOVVC R0,#0
	MOVS PC,R14

S16Hprevhandler	DCD 0,0


	FUNC	Sound16_RemoveHandler
	LDR R1,S16Hprevhandler
	LDR R2,S16Hprevhandler+4
	MOV R0,#1
	SWI XSound_LinearHandler
	MOVVC R0,#0
	MOVS PC,R14


LinearHandler	; R0= parameter
		; R1->buffer to fill
		; R2->end of buffer
		; R3= flags:
		;     bit0-2	0 buffer invalid
		;		1 buffer contains data from 8bit emul.
		;		2 buffer contains all zeros
		; R4= current frequency in Hz (22.10)
	STMFD R13!,{R11,R12,R14}
	AND R3,R3,#7
	TEQ R3,#2			; Buffer already 0?
	BEQ LH_buffer0
	MOV R12,#0
	MOV R0,R1
LH_clearloop
	 STR R12,[R0],#4
	 CMP R0,R2
	BLT LH_clearloop
LH_buffer0
	LDR R12,Sound_ready
	LDR R12,[R12]			; Dereference
	CMP R12,#0			; System ready?
	LDMEQFD R13!,{R11,R12,PC}^
	LDR R9,Sound_chan
	MOV R10,#NUM_CHANNELS		; 8 channels
LH_channelloop
	 LDR R3,[R9]			; R3->base of sample (or 0)
	 TEQ R3,#0
	 BEQ LH_nextchan
	 LDMIB R9,{R4-R8}		; R4= Length
					; R5= Lamp	(10.22) (double)
					; R6= Ramp	(10.22)
					; R7= pitch	(16.16)
					; R8= phase acc (16.16)
	 STMFD R13!,{R1,R9}
	 MOV R9,#&FF
	 ORR R9,R9,#&FF00		; R9 =0000FFFF
LH_fillloop
	  ADD R8,R8,R7			; Advance phase
	  CMP R8,R4,LSL#16
	  BHS LH_gateoff
	  LDRB R0,[R3,R8,LSR#16]	; R0=sample (8bit unsigned)
	  SUBS R0,R0,#128		; R0=signed lin
	  LDR R12,[R1]			; R12=LLLLRRRR
	  BICNE R11,R12,R9		; R11=LLLL0000
	  MOVNE R12,R12,LSL#16		; R12=RRRR0000
	  MLANE R11,R5,R0,R11		; R11=LLLLLLLL
	  MLANE R12,R6,R0,R12		; R12=RRRRRRRR
	  BICNE R11,R11,R9		; R11=LLLL0000
	  ORRNE R12,R11,R12,LSR#16	; R12=LLLLRRRR
	  STR R12,[R1],#4		; Store LR sample
	  CMP R1,R2
	 BLT LH_fillloop
	 LDMFD R13!,{R1,R9}
	 STR R8,[R9,#5*4]		; Update phacc
LH_nextchan
	 ADD R9,R9,#8*4			; sizeof(chan_info)
	 SUBS R10,R10,#1
	BGT LH_channelloop
	LDMFD R13!,{R11,R12,PC}^
LH_gateoff
	  LDMFD R13!,{R1,R9}
	  MOV R3,#0
	  STR R3,[R9,#0]		; Turn off channel
	 B LH_nextchan

; ----------------------------- Music support -----------------------------


	FUNC	Mus_CheckAndInit
	MOV R0,#0
	SWI XMIDI_Init			; check presence
	BVS MCAIfailed
	TEQ R0,#0
	BEQ MCAIfailed
	MOV R0,#15
	SWI XMIDI_Init			; clear queues
	BVS MCAIfailed
	MOV R0,#1
	SWI XMIDI_IgnoreTiming
	MOVVC R0,#1
	MOVVCS PC,R14
MCAIfailed
	MOV R0,#0
	MOVS PC,R14


	FUNC	Mus_ClearQueue
	MOV R0,#15
	SWI XMIDI_Init			; clear buffers
	MOVS PC,R14


	FUNC	Mus_StopSound
	MOV R1,#1
MSScutloop
	 MOV R0,R1
	 SWI XMIDI_SetTxChannel
MSSwaitloop
	  SWI XMIDI_TxAllNotesOff	; loop until sent
	 BVS MSSwaitloop
	 ADD R1,R1,#1
	 CMP R1,#17
	BLO MSScutloop
	MOVS PC,R14


	FUNC	Mus_StartClock
	SWI XMIDI_FastClock		; clock=0
	MOV R0,R1
	MOVS PC,R14


	FUNC	Mus_TxCommand
	ADD R2,R1,R1,LSL#1
	ADD R1,R2,R1,LSL#2		; Time=Time*7 (approx. 1000/140)
	SWI XMIDI_TxCommand
	MVNVS R0,#2			; Return -3 if tx buffer full
	MOVS PC,R14



