📄 qx.s
字号:
;************************************************************************
; Copyright 2000 QSound Labs Inc. All rights reserved.
;
; Revision 1.0
;
;
;
; Module: SUB_Qxpander (2.0 to 2.0)
;
; Initial version: Mark S. Williams (Qsound Labs, Inc.) (19/4/2000
; Calling : Qxpander,QXinitialize,QXsave,QXrestore
; Return: r27
; Param in:
; Temp reg:
; AGR reg:
; Local buffer:
;************************************************************************
;;;
;;; QXpander
;;;
;;; Copyright 2000 QSound Labs Inc. All rights reserved.
;;;
;;; Author: markw@qsound.com April 19, 2000
;;;
;;; QXpander implementation for the LuxSonar DSP
;;;
;;; Modification History
;;;
;;; April 19, 2000 mark.williams@qsound.com
;;;
;;; code based upon qsurround implementation - paired down the processing so
;;; that it only does the qxpander portion of qsurround.
#define REMOVE_HP 0
#define THREE_STAGE 0
//#define QX_44K
.nolist
#include "qx.h"
.list
#if THREE_STAGE
#define NumStages 3
#else
#define NumStages 4
#endif
#define NumDataPerStage 2
.nolist
#include "regdef.h"
#ifdef SOFTWARE
#include "memory.h"
#endif
.list
.text
.if QSOUND
.globl SUB_QXpander
.globl filterCoeffs
.globl m48both
.globl m44both
.set noreorder
;; --------------------------------------------------------------
;; - Code -------------------------------------------------------
;; --------------------------------------------------------------
SUB_QXpander:
jsr r28, QXrestore
dlw r0, QX_flag
movi AGRSiz0,0xffff
movi AGRSiz1,0xffff
movi AGRSiz2,0xffff
movi AGRSiz3,0xffff
movi AGRSiz4,0xffff
tsti r0,0
bne Linit_done
jsr r28, QXInitialise ;copy filter coeffs and states
movi r0, 1
dsw r0, QX_flag
Linit_done:
movi AGRAdr2, local_FApcm_buf_byte
;; Setup address pointers
#if !REMOVE_HP
movi AGRInc1,4
#endif
movi AGRInc4,4
jsr r28, QXpander ;in: local_input
;out: pointed by AGRAdr2
;process 256 samples
;the result should be packed
;as 2-channel in local_FApcm_buf_byte,
;32-bit or 16-bit per channel depending
;on I2S or not
movi AGRSiz7,0xffff
jsr r28, QXsave ;save states
j r27
;; --------------------------------------------------------------
;; QXrestore
; calling: none
; called by: SUB_QXpander
; return: r28
;; This routine restores the status of QXpander.
;; It is called every time when we return to process QXpander.
;; --------------------------------------------------------------
;;; MSW - Changed these to correctly account for the various combinations
;;; of defines.... Any change here needs to be also correctly incorporated
;;; into the rewinding of the ptrs for the next processed sample
#if REMOVE_HP&&THREE_STAGE
#define dmaDataSize (15-1)
#elif REMOVE_HP&&(!THREE_STAGE)
#define dmaDataSize (19-1)
#elif (!REMOVE_HP)&&THREE_STAGE
#define dmaDataSize (19-1)
#elif (!REMOVE_HP)&&(!THREE_STAGE)
#define dmaDataSize (23-1)
#else
// error
#endif
#if REMOVE_HP&&THREE_STAGE
#define dmaCoeffSize (11-1)
#elif REMOVE_HP&&(!THREE_STAGE)
#define dmaCoeffSize (13-1)
#elif (!REMOVE_HP)&&THREE_STAGE
#define dmaCoeffSize (14-1)
#elif (!REMOVE_HP)&&(!THREE_STAGE)
#define dmaCoeffSize (16-1)
#else
// error
#endif
QXrestore:
;; dma read the static variables into local memory
movi r0, dmaData
shr r0, 2 ; convert to word address
movi BlockSize, dmaDataSize
movi BlockSkip, 0
movi DMASize, dmaDataSize
movi LocalAddr, (local_data>>2); convert to word
dmarr r0
waitd: bdb waitd
;; dma read the coeffs variables into local memory
movi r0, dmaCoeffs; convert to word address
shr r0, 2
movi BlockSize, dmaCoeffSize
movi DMASize, dmaCoeffSize
movi LocalAddr, (local_coeffs>>2); convert to word
dmarr r0
waitc: bdb waitc
;; dma read the intermediate buffers into local memory
movi r0, dmaBuf
shr r0, 2 ; convert to word address
movi BlockSize, dmaBufSize
movi DMASize, dmaBufSize
movi LocalAddr,(local_buf>>2); convert to word.
dmarr r0
waite: bdb waite
j r28
;; --------------------------------------------------------------
;; QXInitialise
; calling: none
; called by: SUB_QXpander
; return: r28
;; This routine initialize buffers for QXpander.
;; It is called once at the first time when QXpander is started.
;; It should be called after the QXrestore routine.
;; --------------------------------------------------------------
;; setup the delay ptrs
QXInitialise:
movi AGRMod0,0
movi AGRMod4,0
movi AGRSiz0,0xffff
movi AGRSiz4,0xffff
movi AGRAdr0, local_data
movi r1,LFBuf
#if !REMOVE_HP
mov r0,a0(20) ;; dummy read to move pointer to left qx delay ptr
#else
mov r0,a0(4) ;; dummy read to move pointer to left qx delay ptr
#endif
movi r0,RFBuf
mov a0(4),r1
mov a0(0),r0
;; clear data history for filters
movi AGRAdr0, local_data
movi r1, 0
#if !REMOVE_HP
loop 4,clrHighPassData
mov a0(4), r1
clrHighPassData:
#endif
mov r0,a0(12) ; dummy read to advance ptr to qfilter history buffer
loop NumStages*NumDataPerStage*2,clrQData
mov a0(4), r1
clrQData:
;; clear local memory delay buffers
movi AGRAdr4, LFBuf
nop
loop 8,clrLFronts
mov a4(4), r1
clrLFronts:
movi AGRAdr4, RFBuf
nop
loop 8,clrRFronts
mov a4(4), r1
clrRFronts:
j r28
;; --------------------------------------------------------------
;; QXpander Processing
;; --------------------------------------------------------------
; calling: none
; called by: SUB_QXpander
; return: r28
;;
;; Calling convention:
;; in: AGRAdr2 (location to save data)
;; Registers preserved:
;;
;----------------------------------------------------------------
QXpander:
;; Setup i/o pointer
;; do not trash a0 in the code
movi AGRAdr0,local_input ; Input pointer
movi AGRAdr1, local_data
movi AGRAdr4, local_coeffs ;; starting with the scale multipliers
mupi r14, 0x007f
ori r14, 0xffff
;; Process the data samples.
loop 256,_QXloop
.if 1 //debug
;; Apply attenuation to LF and RF
movhf r0, a0(2)
mulf r16,r0,a4(4) ; LF
movhf r0, a0(2)
mulf r18,r0,a4(4) ; RF
;; Apply high pass filter
;; rnd only works on the multiplier! so set things up so that
;; we use the adder portion of the multiplier
#if !REMOVE_HP
;; r20/r21 = HP(LF)
mulf r22,i1,a4(4) ; d1*f1 a4-> q1/2
nop ; MSW - is required
mov r15,a4(4) ; r15=q1/2 a4-> 1.0
madd r22,r14,a1(-4) ; d2+d1*f1 (LP)
mulf r10,r15,a1(0) ; q1/2*d1
madd r10,r15,a1(0) ; q1*d1
madd r10,r22,a4(4) ; q1*d1+LP a4-> FrontSpread
mulf r20,r16,a4(-4) ; LF a4-> 1.0
msub r20,r10,a4(-8) ; (LF) - (LP + q1*d1) (HP) !!! a4->f1
nop // necessary
rnd r20
mulf r10,r14,a1(4) ; d1
madd r10,r20,a4(0) ; d1 + HP*f1
rnd a1(-4),r22 ; update LP with rounding and saturation
rnd a1(8),r10 ; update BP with rounding and saturation
nop ;; MSW this nop is required...
;; r22/r23 = HP(RF+RS)
mulf r12,i1,a4(4) ; d1*f1
nop ; MSW - is required
mov r15,a4(4) ; r15=q1/2 a4-> 1.0
madd r12,r14,a1(-4) ; d2 + d1*f1 (LP)
mulf r10,r15,a1(0) ; q1/2*d1
madd r10,r15,a1(0) ; q1*d1
madd r10,r12,a4(4) ; LP+q1*d1 a4 -> FrontSpread
mulf r22,r18,a4(-4) ; RF a4-> 1.0
msub r22,r10,a4(-8) ; (HP) a4->f1
nop // necessary
rnd r22
mulf r10,r14,a1(4) ; d1
madd r10,r22,a4(12) ; d1 + HP*d1 (BP) advance a4
rnd a1(-4),r12 ; update LP with rounding and saturation
rnd a1(8),r10 ; update BP with rounding and saturation
;; Apply Scott Fix
mulf r10,r18,a4(0) ; Front spread
mulf r12,r16,a4(4) ; Front spread a4->sf
msub r20,r10,a4(0) ; HP - r18*sf*frontspread
msub r22,r12,a4(4) ; HP - r16*sf*frontspread a4->a0
#else
mulf r20,r16,a4(0) ; a4-> spread. Part of panner complex
mulf r22,r18,a4(0) ; a4-> spread. Part of panner complex
#endif
;; Apply QX delay to LF and RF, mix into LFoutput and RFoutput
mov r0,a1(4) ; QX delay
mov r1,a1(0) ; LF direct pointer
mov AGRSiz7,r0 ;
mov AGRAdr7,r1 ; LF direct pointer
#if !REMOVE_HP
nop
#else
mulf r10,r18,a4(0) ; Front Part of Scott fix
#endif
rnd a7(4),r16 ; store LF with rnd
mov r1,AGRAdr7
#if !REMOVE_HP
nop
#else
mulf r12,r16,a4(4) ; Front a4->sf part of scott fix
#endif
mov a1(4),r1
mulf r4,r14,a7(0) ; LFoutput =delay(LF*FLatten)
mov r1,a1(0) ; RF direct pointer
nop
mov AGRAdr7,r1 ; RF direct pointer
#if !REMOVE_HP
nop
#else
msub r20,r10,a4(0) ; HP - r18*sf*frontspread. Part of scott fix
#endif
rnd a7(4),r18 ; store RF with rnd
mov r1,AGRAdr7
#if !REMOVE_HP
nop
#else
msub r22,r12,a4(4) ; HP - r16*sf*frontspread. Part of scott fix
#endif
mov a1(4),r1
mulf r6,r14,a7(0) ; RFoutput =delay(RF*FRatten)
;; now r16/17 and r18/19 are avalible
;; Apply Q Filter, mix into LFoutput and RFoutput
;; at the top of qfilter assume these conditions a4 points to first coeff
;; this needs to be set up from the highpass coeffs
;; assume a1 ptrs to history buffer
mulf r20,r20,a4(0)
mulf r22,r22,i4
loop (NumStages-1),endqloop
mov r17,i4 ;;
msub r20,r17,a1(0)
msub r20,r17,a1(4) ;; a1 ->
msub r22,r17,a1(0)
msub r22,r17,a1(4)
mov r17,i4
msub r20,r17,a1(4)
msub r22,r17,a1(-12)
mov r17,a1(0)
rnd a1(8),r20
mov a1(-4),r17
mov r17,a1(0)
rnd a1(8),r22
mov a1(4),r17
endqloop:
mov r17,i4 ;;
msub r20,r17,a1(0)
msub r20,r17,a1(4) ;; a1 ->
msub r22,r17,a1(0)
msub r22,r17,a1(4)
#if REMOVE_HP&&THREE_STAGE
mov r17,a4(-40)
#elif REMOVE_HP&&(!THREE_STAGE)
mov r17,a4(-48)
#elif (!REMOVE_HP)&&THREE_STAGE
mov r17,a4(-52)
#elif (!REMOVE_HP)&&(!THREE_STAGE)
mov r17,a4(-60)
#endif
msub r20,r17,a1(4)
msub r22,r17,a1(-12)
mov r17,a1(0)
rnd a1(8),r20
mov a1(-4),r17
mov r17,a1(0)
// msw fixed this...
// j.h was saving the z-1 into the z-2 history for the right side filter.
// correctly bu the code I've gotten from Richard and Tan lately hasn't been...
rnd a1(8),r22
#if 1
// either have a nop in here so that the r22 value settles into memory or rewind
// further to the r20 value and do the right addition first.
;;; VERY IMPORTANT use this version of the code not the block below.
;;; the block below doesnot behave correctly it should - msw will have
;;; a look at this.
mov a1(-8),r17 ; a1-> z-1 of right filter which is added to left channel
nop;
madd r4, r14,a1(-4) ; to r20 position
#if REMOVE_HP&&THREE_STAGE
madd r6, r14,a1(-44)
#elif REMOVE_HP&&(!THREE_STAGE)
madd r6, r14,a1(-60)
#elif (!REMOVE_HP)&&THREE_STAGE
madd r6, r14,a1(-60)
#elif (!REMOVE_HP)&&(!THREE_STAGE)
madd r6, r14,a1(-76)
#else
error
#endif
#else
mov a1(-12),r17 ; a1-> z-1 of left filter which is added to right channel
madd r6, r14,a1(4) ; to r20 position
#if REMOVE_HP&&THREE_STAGE
madd r4, r14,a1(-48)
#elif REMOVE_HP&&(!THREE_STAGE)
madd r4, r14,a1(-64)
#elif (!REMOVE_HP)&&THREE_STAGE
madd r4, r14,a1(-64)
#elif (!REMOVE_HP)&&(!THREE_STAGE)
madd r4, r14,a1(-80)
#else
error
#endif
#endif
;; Update current group with QSurround results
#ifdef I2S
rnd a2(4),r4 ;; write LF input
rnd a2(4),r6 ;; write LR input
#else
rndhf a2(2), r4 ;L. middle 16-bit ?
rndhf a2(2), r6 ;R. to L of next sample
#endif
.else
movhf r4, a0(2) ;
movhf r6, a0(2) ; a0 ->LF
nop
nop
#ifdef I2S
mov a2(4), r4
mov a2(4), r6
#else
movhf a2(2), r4 ;L. middle 16-bit ?
movhf a2(2), r6 ;R. to L of next sample
#endif
.endif //debug
_QXloop:
j r28 ; return
;; --------------------------------------------------------------
;; QXsave
;; --------------------------------------------------------------
; calling: none
; called by: SUB_QXpander
; return: r28
;;
;;
;----------------------------------------------------------------
QXsave:
;; dma write the intermediate states into DRAM
movi r0, dmaData
shr r0, 2 ; convert to word address
movi BlockSize, dmaDataSize
movi DMASize, dmaDataSize
movi LocalAddr, (local_data>>2); convert to word?
dmawr r0
waits: bdb waits
;; dma write the intermediate buffers into DRAM
movi r0, dmaBuf
shr r0, 2 ; convert to word address
movi BlockSize, dmaBufSize
movi DMASize, dmaBufSize
movi LocalAddr, (local_buf>>2); convert to word?
dmawr r0
wait4: bdb wait4
j r28
#ifdef SOFTWARE
.rdata //in different section
#else
.data
#endif
dmaData:
.align 4
#if !REMOVE_HP
.word 0x00000000 ;; d1 left
.word 0x00000000 ;; d2 left
.word 0x00000000 ;; d1 right
.word 0x00000000 ;; d2 right
#endif
.word 0x0000001c ;; qx delay (7 samples)
.word 0x00000000 ;; qx ptr left (needs to be set)
.word 0x00000000 ; qx ptr right
.word 0x00000000 ;; data buffer (alternates left right)
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
#if !THREE_STAGE
.word 0x00000000
.word 0x00000000
.word 0x00000000
.word 0x00000000
#endif
dmaCoeffs:
.align 4
#if 0
.word 0x004026E7 ;; lf mult
.word 0x004026E7 ;; rf mult
#else
.word 0x005FFC87 ;; lf mult
.word 0x005FFC87 ;; rf mult
#endif
#if !REMOVE_HP
.word 0x0001d7d2 ;; f1 (should be 110 Hz @ 48k)
.word 0x005A8279 ;; q1/2
.word 0x007FFFFF ; 1.0
#endif
.word 0x007fffff ;; Spread
.word 0x007fffff ;; sf (0dB)
filterCoeffs:
;; default: 44.1K filters (m44both4.bri or m44both3.bri)
#if !THREE_STAGE
.word 0xFFFFED63 ;; a0
.word 0xFF8A6B6B ;; a1/2
.word 0x006E3B46 ;; a2
.word 0xFF9AE438 ;; a1/2
.word 0x00607031 ;; a2
.word 0xFFA0CE26 ;; a1/2
.word 0x006AB262 ;; a2
.word 0xFFA62933 ;; a1/2
.word 0x007674F2 ;; a2
#else
.word 0xFFFFDC07 ;; a0
.word 0xFF8AB642 ;; a1/2
.word 0x006DC1C5 ;; a2
.word 0xFF97FB8A ;; a1/2
.word 0x006687FB ;; a2
.word 0xFF9A4460 ;; a1/2
.word 0x007559E7 ;; a2
#endif
m44both:
;; 44.1K filters (m44both4.bri or m44both3.bri)
#if !THREE_STAGE
.word 0xFFFFED63 ;; a0
.word 0xFF8A6B6B ;; a1/2
.word 0x006E3B46 ;; a2
.word 0xFF9AE438 ;; a1/2
.word 0x00607031 ;; a2
.word 0xFFA0CE26 ;; a1/2
.word 0x006AB262 ;; a2
.word 0xFFA62933 ;; a1/2
.word 0x007674F2 ;; a2
#else
.word 0xFFFFDC07 ;; a0
.word 0xFF8AB642 ;; a1/2
.word 0x006DC1C5 ;; a2
.word 0xFF97FB8A ;; a1/2
.word 0x006687FB ;; a2
.word 0xFF9A4460 ;; a1/2
.word 0x007559E7 ;; a2
#endif
;; 48K filters (m48both4.bri or m48both3.bri)
m48both:
#if !THREE_STAGE
.word 0xFFFFF545 ;; a0
.word 0xFFA15E5E ;; a1/2
.word 0x007674F2 ;; a2
.word 0xFF9D3A0C ;; a1/2
.word 0x006BC04D ;; a2
.word 0xFF989590 ;; a1/2
.word 0x0061DCC7 ;; a2
.word 0xFF89F91A ;; a1/2
.word 0x006ED4F4 ;; a2
#else
.word 0xFFFFE7B6 ;; a0
.word 0xFF89F91A ;; a1/2
.word 0x006ED4F4 ;; a2
.word 0xFF960027 ;; a1/2
.word 0x0067AE13 ;; a2
.word 0xFF971FEB ;; a1/2
.word 0x007674F2 ;; a2
#endif
dmaBuf: .align 2
.fill 64,4,0
QX_flag: .align 2
.word 0x00000000
.endif //QSOUND
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -