| @*********************************************************** | |
| @ Function: WT_InterpolateNoLoop | |
| @ Processor: ARM-E | |
| @ Description: the main synthesis function when fetching | |
| @ wavetable samples. | |
| @ C-callable. | |
| @ | |
| @ Usage: | |
| @ void WT_InterpolateNoLoop( | |
| @ S_WT_VOICE *pWTVoice, | |
| @ S_WT_FRAME *pWTFrame); | |
| @ | |
| @ Copyright Sonic Network Inc. 2004 | |
| @**************************************************************** | |
| @ Revision Control: | |
| @ $Revision: 496 $ | |
| @ $Date: 2006-12-11 14:33:26 -0800 (Mon, 11 Dec 2006) $ | |
| @**************************************************************** | |
| @ | |
| @ where: | |
| @ S_WT_VOICE *pWTVoice | |
| @ PASSED IN: r0 | |
| @ | |
| @ S_WT_FRAME *pWTFrame; | |
| @ PASSED IN: r1 | |
| @**************************************************************** | |
| .include "ARM_synth_constants_gnu.inc" | |
| .arm | |
| .text | |
| .global WT_InterpolateNoLoop | |
| @ Register usage | |
| @ -------------- | |
| pWTVoice .req r0 | |
| pWTFrame .req r1 | |
| pOutputBuffer .req r2 | |
| numSamples .req r3 | |
| phaseIncrement .req r4 | |
| pPhaseAccum .req r5 | |
| phaseFrac .req r6 | |
| phaseFracMask .req r7 | |
| tmp0 .req r1 @ reuse register | |
| tmp1 .req r8 | |
| tmp2 .req r9 | |
| @SaveRegs RLIST {r4-r9,lr} | |
| @RestoreRegs RLIST {r4-r9,pc} | |
| .func WT_InterpolateNoLoop | |
| WT_InterpolateNoLoop: | |
| STMFD sp!, {r4-r9,lr} | |
| @ | |
| @ Fetch parameters from structures | |
| @---------------------------------------------------------------- | |
| LDR pOutputBuffer, [pWTFrame, #m_pAudioBuffer] | |
| LDR numSamples, [pWTFrame, #m_numSamples] | |
| LDR phaseIncrement, [pWTFrame, #m_phaseIncrement] | |
| LDR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] | |
| LDR phaseFrac, [pWTVoice, #m_phaseFrac] | |
| LDR phaseFracMask,=PHASE_FRAC_MASK | |
| InterpolationLoop: | |
| .ifdef SAMPLES_8_BIT | |
| LDRSB tmp0, [pPhaseAccum] @ tmp0 = x0 | |
| LDRSB tmp1, [pPhaseAccum, #1] @ tmp1 = x1 | |
| .else | |
| LDRSH tmp0, [pPhaseAccum] @ tmp0 = x0 | |
| LDRSH tmp1, [pPhaseAccum, #2] @ tmp1 = x1 | |
| .endif | |
| ADD tmp2, phaseIncrement, phaseFrac @ increment pointer here to avoid pipeline stall | |
| SUB tmp1, tmp1, tmp0 @ tmp1 = x1 - x0 | |
| SMULBB tmp1, phaseFrac, tmp1 @ tmp1 = phaseFrac * tmp2 | |
| @ This section performs a gain adjustment of -12dB for 16-bit samples | |
| @ or +36dB for 8-bit samples. For a high quality synthesizer, the output | |
| @ can be set to full scale, however if the filter is used, it can overflow | |
| @ with certain coefficients and signal sources. In this case, either a | |
| @ saturation operation should take in the filter before scaling back to | |
| @ 16 bits or the signal path should be increased to 18 bits or more. | |
| .ifdef SAMPLES_8_BIT | |
| MOV tmp0, tmp0, LSL #6 @ boost 8-bit signal by 36dB | |
| .else | |
| MOV tmp0, tmp0, ASR #2 @ reduce 16-bit signal by 12dB | |
| .endif | |
| ADD tmp1, tmp0, tmp1, ASR #(NUM_EG1_FRAC_BITS-6) @ tmp1 = tmp0 + (tmp1 >> (15-6)) | |
| @ = x0 + f * (x1 - x0) == interpolated result | |
| STRH tmp1, [pOutputBuffer], #NEXT_OUTPUT_PCM @ *pOutputBuffer++ = interpolated result | |
| @ carry overflow from fraction to integer portion | |
| ADD pPhaseAccum, pPhaseAccum, tmp2, LSR #(NUM_PHASE_FRAC_BITS - NEXT_INPUT_PCM_SHIFT) | |
| AND phaseFrac, tmp2, phaseFracMask @ nphaseFrac = frac part | |
| SUBS numSamples, numSamples, #1 | |
| BGT InterpolationLoop | |
| @ Clean up and store any changes that were caused during the loop | |
| @---------------------------------------------------------------- | |
| @ update and store phase | |
| STR pPhaseAccum, [pWTVoice, #m_pPhaseAccum] | |
| STR phaseFrac, [pWTVoice, #m_phaseFrac] | |
| @ | |
| @ Return to calling function | |
| @---------------------------------------------------------------- | |
| LDMFD sp!,{r4-r9,lr} | |
| BX lr | |
| .endfunc | |
| .end | |