Даа, я естественно тоже пришел к выводу, что там возня лишняя присутствует.
И ресурсы как памяти так и проца расходуются непонятно куда.
t->InBuf - входной буфер RealFFT
in - комплексный вывод того самого RealFFT
in в формате принятом в Speex. А именно R[0],R[1],I[1],R[2],I[2]....R[N/2]
Код
t->InBuf[0]=in[0];
for (i=1, j=1; i<(t->FFTSize/2); i++){
t->InBuf[i]=in[j]+in[j+1];
j+=2;
}
t->InBuf[t->FFTSize/2]=in[t->FFTSize-1];
for (i=t->FFTSize/2+1, j=(t->FFTSize-3); i<(t->FFTSize); i++){
t->InBuf[i]=in[j]-in[j+1];
j-=2;
}
А это из техасовского комплексного вывода делает вещественный.
Как последний шаг моей IFFT.
t->OutBuf - комплексный вывод техасовского RFFT в формате R[0],R[1],R[2]....R[N/2],I[N/2-1],I[N/2-2]....I[1]
out - вывод функции, где в итоге получается восстановленый сигнал(in time domain)
Код
out[0]=t->OutBuf[0];
for (i=1; i<(t->FFTSize/2);i++)
out[i]=t->OutBuf[i] + t->OutBuf[t->FFTSize-i];
out[i++]=t->OutBuf[i];
for (; i<(t->FFTSize);i++)
out[i]=t->OutBuf[t->FFTSize-i] - t->OutBuf[i];
Функция "перепаковывающая" техасовский вывод в формат, принятый в Speex
Код
;static void _TMStoSPEEXrepack(spx_word16_t *SPXpacked, spx_word16_t *TMSpacked, int N){
;//перепаковывает рузультаты FFT в формат принятый в speex
;//TMSpacked[0] = real[0] TMSpacked[1] = real[1].... TMSpacked[N/2] = real[N/2]
;//TMSpacked[N-1] = imag[1] TMSpacked[N-2] = imag[2].... TMSpacked[N/2+1] = imag[N/2-1]
;//SPXpacked = R(0),R(1),I(1),R(2),I(2)....R(N/2)
;
;SPXpacked XAR4
;TMSpacked XAR5
;N AL
.global __TMStoSPEEXrepack
.sect "ramfuncs"
__TMStoSPEEXrepack:
PUSH AL
;расчитаем указатель на imag[N/2-1]
MOVL ACC,XAR5
ADD ACC,*-SP[1]
ADD ACC,*-SP[1];второй раз потому что float занимает 2слова
MOVL XAR6,ACC;XAR6 указывает на TMSpacked[N-1] т.е. на imag[1]
;подготовить счётчик цикла
POP AL
LSR AL#1
ADD AL,#-2;цикл должен пройти N/2-1 раз
;до начала цикла делаем
;SPXpacked[0]=TMSpacked[0];
MOV32 R0H,*XAR5++
MOV32 *XAR4++,R0H
.align 2
NOP
RPTB fftrepack_loop,AL
MOV32 R0H,*XAR5++;real[i]
MOV32 *XAR4++,R0H
MOV32 R0H,*--XAR6;imag[i]
MOV32 *XAR4++,R0H
fftrepack_loop:
MOV32 R0H,*XAR5++;real[i]
MOV32 *XAR4++,R0H
LRETR
А это чтбы быстро перемножить буфер на множитель, попутно скопировав результат в другой буфер. Также работает "на месте" - т.е. с одним буфером.
Код
;void asm_mul_by_const(float* dst, float* src, float mul, int len);
;dst XAR4
;src XAR5
;mul R0H
;len AL
;умножает каждый элемент src на mul результат ложится в dst
;dst[i]=src[i]*mul
.global _asm_mul_by_const
.sect "ramfuncs"
_asm_mul_by_const:
LSR AL,#1;цикл unrolled, так что делим счётчик на 2
ADDB AL,#-1; чтобы RPTB не перестарался
RPTB asm_mul_by_const_loop,AL
MOV32 R1H,*XAR5++;R1H=src[i]
MPYF32 R1H,R1H,R0H;R1H=src[i]*mul
MOV32 R2H,*XAR5++;R2H=src[i+1]
MPYF32 R2H,R2H,R0H;R2H=src[i+1]*mul
MOV32 *XAR4++,R1H;dst[i]=R1H
MOV32 *XAR4++,R2H;dst[i+1]=R1H
asm_mul_by_const_loop:
LRETR
Остались эти speexComplex_to_real() и TMScomplex_to_real() оптимизировать.
На сях они кушают непомерно много даже со всеми оптимизациями компилятора и прочими премудростями.
Обидно, когда тупое копирование буферов занимает по тактам половину времени расчёта FFT
The truth is out there...