@; Sound buffer fill code
@; ----------------------
@; This code is relocated before being used

.set X_Bit, 0x20000
.set XSharedSound_RemoveHandler, 0x04B441 + X_Bit

    .text
    .align 2

    .global ss_start
    .global ss_buffer_fill
    .global ss_error_handler
    .global ss_circ_buffer
    .global ss_end

ss_start: @; start of block to copy

@; shared sound buffer fill function
@; ---------------------------------
ss_buffer_fill:
    @; r0 = our parameter        (unused)
    @; r1 = buffer base          (used and saved, for info)
    @; r2 = buffer end           (used and saved, for info)
    @; r3 = flags                (used)
    @; r4 = Sample frequency     (not used but saved, for info)
    @; r5 = Sample period        (ignored)
    @; r6 = Fractional step      (used and saved, for info)
    @; r7 = LR volume            (ignored)
    @; r8 = Pointer to fill code (ignored)

    @; First, check if we need to clear the buffer or add to it
    tst r3, #1
    orr r3, r3, #1             @; inform caller we will have written data
    stmfd sp!, {r0-r10,lr}
    bne nozeros
    mov r9, #0
    mov r10, r1  @; buffer base
zeroloop:
    str r9, [r10], #4
    cmp r10, r2
    blt zeroloop
nozeros:
    adr r0, ss_circ_buffer+base
    stmia r0, {r1,r2,r4,r6}    @; save some values passed to us

    sub r0, r0, #base          @; point back to ss_circ_buffer
    ldmia r0, {r7-r10}         @; load data structure
    @; r7 = buffer size (samples not bytes)
    @; r8 = read index  (samples not bytes)
    @; r9 = write index (samples not bytes)
    @; r10 = fractional rate accumulator (8.24 fixed point)
    ldr r3, [r0, #buffer]      @; source buffer start address

samploop:
    cmp r8, r9
    beq exit                   @; source buffer empty (underrun), exit

    ldr r4, [r1]               @; load destination data
    ldr r5, [r3, r8, lsl #2]   @; load source data
    add r4, r4, r5             @; combine (Note - no overflow checks!)
    str r4, [r1], #4           @; store new destination data, point to next

    add r10, r10, r6           @; point to next source sample
    add r8, r8, r10, lsr #24   @; using fractional step
    bic r10, r10, #0xFF000000
    cmp r8, r7
    subge r8, r8, r7           @; wrap index

    cmp r1, r2                 @; Check for buffer end
    blt samploop
exit:
    str r8, [r0, #read]        @; update read index
    str r10, [r0, #rate_acc]   @; update fractional rate accumulator
    ldmfd sp!, {r0-r10,pc}     @; exit


@; shared sound error handler function
@; -----------------------------------
ss_error_handler:
    stmfd sp!, {r0-r2,lr}
    mrs r2, cpsr
    adr r1, ss_circ_buffer
    ldr r0, [r1, #handler_id]
    cmp r0, #0                 @; Check if sound handler installed
    swine XSharedSound_RemoveHandler @; if installed, remove it
    mov r0, #0
    str r0, [r1, #handler_id]  @; ensure id is cleared
    msr cpsr_f, r2
    ldmfd sp!, {r0-r2,pc}


@; source buffer structure
@; --------------------------------
ss_circ_buffer:
@; structure offsets, must agree with 'c' declaration
.set size,         0  @; length in samples of circular data buffer
.set read,         4  @; read index
.set write,        8  @; write index
.set rate_acc,    12  @; rate accumulator (8.24 fixed point)
.set handler_id,  16  @; sound handler id
.set base,        20  @; dest buffer start
.set end,         24  @; dest buffer end
.set sample_freq, 28  @; system sample rate (1/1024 Hz)
.set step,        32  @; fractional step (8.24)
.set buffer,      36  @; address of buffer
    .skip 40

ss_end:  @; end of block to copy


