Entry | |
---|---|
R0 | Address of handler |
R1 | Parameter passed to handler |
R2 | Flags |
R3 | Address of handler name |
R4 | Type |
Exit | |
---|---|
R0 | Handler number if successful (V clear) |
Flags | |
---|---|
Bit 0 | if set then use type in R4 otherwise set type to default. |
Type | |
---|---|
0 | Immediate handler |
1 | Call back handler |
2 | Process handler |
Each handler is called when the current driver is called if the handler is an immediate handler or on call back if the handler is either a call back or process handler. The handlers in each type are called in the order in which they were installed. Process handlers are called after call back handlers.
Each handler is passed a buffer to fill with the registers set as follows:
R0 | parameter |
R1 | base address of buffer to fill |
R2 | end of buffer |
R3 | flags |
Bit 0 If set then data must be mixed otherwise overwrite. | |
Bit 30 Set if the volume in R7 is not equal to 0xFFFFFFFF | |
Bit 31 Set if the volume in R7 is 0 (i.e. sound is muted) | |
All other bits are currently passed as 0, but it is anticipated that they may be used in the following way in future revisions of the module: | |
Bit 1 If set then use highest quality e.g. oversampling. | |
Bits 3-7 Overrun count | |
0 No overrun | |
1—30 Number of times buffer has been overrun | |
31 Buffer has been overrun by more than 30 times | |
Bit 29 Stereo. Reverse stereo if set. | |
R4 | sample frequency |
R5 | sample period |
R6 | fractional step as specified by SharedSound_SampleRate |
R7 | LR volume |
R8 | Pointer to table of helpful fill routines |
R4, R5 and R6 are set by SharedSound to the current values as passed in from the lower level Sound Handler, thus may change between calls to the clients handler.
On exit
R3 contains flags as above, modified according to the action of the handler. The important requirement on exit is that bit 0 of R3 should be set if any data has been written into the buffer. In fact, SharedSound cannot currently cope with no data being filled, so zeros should always be written.
Helpful fill routines
On entry to the fill code, R8 points to a table in the following format:
[R8,#0]=Flags word; currently 0.
[R8,#4]=Pointer to silence fill routine.
[R8,#8]=Pointer to data fill routine.
This table may be extended in future to include more fill variants; it is anticipated that the presence/absence of these routines will be indicated by bits in the flag word.
The data fill routine is called in the following way:
On Entry | |
---|---|
R1 | Base address of buffer to be filled |
R2 | End of the buffer to be filled |
R3 | Flags (as on entry to the fill routine) |
R4 | Base of buffer to fill from |
R5 | End of buffer to fill from |
R6 | Fractional step value |
R7 | LR volume |
R9 | Fractional accumulator |
On Exit | |
---|---|
R0 | New flags (to be returned from fill handler in R3) |
R1 | Next byte to be filled |
R4 | Next byte to fill from |
R9 | New Fractional accumulator |
R2,R3,R5,R6,R7,R8,R12 preserved | |
All other registers corrupted. |
The fill code will fill/mix from the given buffer to the output buffer. It will return either when the buffer is filled, or when it runs out of data.
The silence code is identical except that R4 and R5 are not used, and no data is read; the code fills/mixes zeros.
The silence/data fill code entry points understand all the currently defined flags in R3. The intention is that if future flags are added to R3 then the supplied fill routines will be extended to understand them too.
This should provide a degree of forwards compatibility.
The overall sound fill code in a client can therefore look something like this (assuming the client is filling from a cyclic buffer):
fill STMFD r13!,{r0-r2,r4-r12,r14}
MOV r12,r0
; We are filling from play_ptr to where?
LDR r4,play_ptr
LDR r5,fill_ptr
LDR r9,buffer_start
ADD r4,r4,r9
ADD r5,r5,r9
LDR r9,accumulator
; Are we wrapped, or unwrapped?
CMP r4,r5
BEQ out_of_data
BLO unwrapped
; |*————————————-********|
; ^fill ptr ^play ptr
LDR r5,buffer_end ; Fill from fill ptr to buffer_end
; Call the fill code
MOV R14,PC
LDR PC,[R8,#8]
; Did we run out of data?
CMP R4,R5 ;
LDRHS R4,buffer_start ; If r4 >= r5 then we used all the
; data in the buffer.
CMP R1,R2 ; Did we finish the fill?
BHS finish ; If r1 >= r2 then we finished.
LDR R5,fill_ptr ; No, so we ran out of data. Jump
CMP R5,#0 ; Check if there any data there -
BEQ out_of_data ; If not, play silence.
ADD R5,R5,R4
unwrapped
; |——-*************************————|
; ^play ptr ^fill ptr
; Call the fill code
MOV R14,PC
LDR PC,[R8,#8]
; Either we finished the fill, or we ran out of data.
CMP R1,R2 ; Did we finish?
BEQ finish
out_of_data
; Fill with silence
MOV R14,PC
LDR PC,[R8,#4]
finish
LDR r3,buffer_start
STR R9,accumulator
SUB r4,r4,r3
STR R4,play_ptr
MOV r3,r0LDMFD r13!,{r0-r2,r4-r12,PC}