/* Copyright (C) 2003 Azimer Copyright (C) 2001,2006-2007 StrmnNrmn This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // // N.B. This source code is derived from Azimer's Audio plugin (v0.55?) // and modified by StrmnNrmn to work with Daedalus PSP. Thanks Azimer! // Drop me a line if you get chance :) // #include #include "stdafx.h" #include "HLEAudio/HLEAudioInternal.h" #include "HLEAudio/HLEAudioState.h" #include "Base/MathUtil.h" #include "Utility/FastMemcpy.h" inline s32 FixedPointMulFull16( s32 a, s32 b ) { return s32( ( (s64)a * (s64)b ) >> 16 ); } inline s32 FixedPointMul16( s32 a, s32 b ) { return s32( ( a * b ) >> 16 ); } inline s32 FixedPointMul15( s32 a, s32 b ) { return s32( ( a * b ) >> 15 ); } void SPNOOP( AudioHLECommand command ) {} void UNKNOWN( AudioHLECommand command ) {} void AudioHLEState::ClearBuffer( u16 addr, u16 count ) { // XXXX check endianness memset( Buffer+(addr & 0xfffc), 0, (count+3) & 0xfffc ); } void AudioHLEState::EnvMixer( u8 flags, u32 address ) { //static // ********* Make sure these conditions are met... *********** /*if ((InBuffer | OutBuffer | AuxA | AuxC | AuxE | Count) & 0x3) { MessageBox (nullptr, "Unaligned EnvMixer... please report this to Azimer with the following information: RomTitle, Place in the rom it occurred, and any save state just before the error", "AudioHLE Error", MB_OK); }*/ // ------------------------------------------------------------ s16 *inp=(s16 *)(Buffer+InBuffer); s16 *out=(s16 *)(Buffer+OutBuffer); s16 *aux1=(s16 *)(Buffer+AuxA); s16 *aux2=(s16 *)(Buffer+AuxC); s16 *aux3=(s16 *)(Buffer+AuxE); s32 MainR; s32 MainL; s32 AuxR; s32 AuxL; s32 i1,o1,a1,a2=0,a3=0; u16 AuxIncRate=1; s16 zero[8]; memset(zero,0,16); s32 LVol, RVol; s32 LAcc, RAcc; s32 LTrg, RTrg; s16 Wet, Dry; u32 ptr = 0; s32 RRamp, LRamp; s32 LAdderStart, RAdderStart, LAdderEnd, RAdderEnd; s32 oMainR, oMainL, oAuxR, oAuxL; s16* buff = (s16*)(rdram+address); //envmixcnt++; //fprintf (dfile, "\n----------------------------------------------------\n"); if (flags & A_INIT) { LVol = ((VolLeft * VolRampLeft)); RVol = ((VolRight * VolRampRight)); Wet = EnvWet; Dry = EnvDry; // Save Wet/Dry values LTrg = (VolTrgLeft << 16); RTrg = (VolTrgRight << 16); // Save Current Left/Right Targets LAdderStart = VolLeft << 16; RAdderStart = VolRight << 16; LAdderEnd = LVol; RAdderEnd = RVol; RRamp = VolRampRight; LRamp = VolRampLeft; } else { // Load LVol, RVol, LAcc, and RAcc (all 32bit) // Load Wet, Dry, LTrg, RTrg Wet = *(s16 *)(buff + 0); // 0-1 Dry = *(s16 *)(buff + 2); // 2-3 LTrg = *(s32 *)(buff + 4); // 4-5 RTrg = *(s32 *)(buff + 6); // 6-7 LRamp = *(s32 *)(buff + 8); // 8-9 (MixerWorkArea is a 16bit pointer) RRamp = *(s32 *)(buff + 10); // 10-11 LAdderEnd = *(s32 *)(buff + 12); // 12-13 RAdderEnd = *(s32 *)(buff + 14); // 14-15 LAdderStart = *(s32 *)(buff + 16); // 12-13 RAdderStart = *(s32 *)(buff + 18); // 14-15 } if(!(flags&A_AUX)) { AuxIncRate=0; aux2=aux3=zero; } oMainL = (Dry * (LTrg>>16) + 0x4000) >> 15; oAuxL = (Wet * (LTrg>>16) + 0x4000) >> 15; oMainR = (Dry * (RTrg>>16) + 0x4000) >> 15; oAuxR = (Wet * (RTrg>>16) + 0x4000) >> 15; for (s32 y = 0; y < Count; y += 0x10) { if (LAdderStart != LTrg) { //LAcc = LAdderStart; //LVol = (LAdderEnd - LAdderStart) >> 3; //LAdderEnd = ((s64)LAdderEnd * (s64)LRamp) >> 16; //LAdderStart = ((s64)LAcc * (s64)LRamp) >> 16; // Assembly code which this replaces slightly different from commented out code above... u32 orig_ladder_end = LAdderEnd; LAcc = LAdderStart; LVol = (LAdderEnd - LAdderStart) >> 3; LAdderEnd = FixedPointMulFull16( LAdderEnd, LRamp ); LAdderStart = orig_ladder_end; } else { LAcc = LTrg; LVol = 0; } if (RAdderStart != RTrg) { //RAcc = RAdderStart; //RVol = (RAdderEnd - RAdderStart) >> 3; //RAdderEnd = ((s64)RAdderEnd * (s64)RRamp) >> 16; //RAdderStart = ((s64)RAcc * (s64)RRamp) >> 16; u32 orig_radder_end = RAdderEnd; RAcc = RAdderStart; RVol = (orig_radder_end - RAdderStart) >> 3; RAdderEnd = FixedPointMulFull16( RAdderEnd, RRamp ); RAdderStart = orig_radder_end; } else { RAcc = RTrg; RVol = 0; } for (s32 x = 0; x < 8; x++) { i1=(s32)inp[ptr^1]; o1=(s32)out[ptr^1]; a1=(s32)aux1[ptr^1]; if (AuxIncRate) { a2=(s32)aux2[ptr^1]; a3=(s32)aux3[ptr^1]; } // TODO: here... //LAcc = LTrg; //RAcc = RTrg; LAcc += LVol; RAcc += RVol; if (LVol <= 0) { // Decrementing if (LAcc < LTrg) { LAcc = LTrg; LAdderStart = LTrg; MainL = oMainL; AuxL = oAuxL; } else { MainL = (Dry * ((s32)LAcc>>16) + 0x4000) >> 15; AuxL = (Wet * ((s32)LAcc>>16) + 0x4000) >> 15; } } else { if (LAcc > LTrg) { LAcc = LTrg; LAdderStart = LTrg; MainL = oMainL; AuxL = oAuxL; } else { MainL = (Dry * ((s32)LAcc>>16) + 0x4000) >> 15; AuxL = (Wet * ((s32)LAcc>>16) + 0x4000) >> 15; } } if (RVol <= 0) { // Decrementing if (RAcc < RTrg) { RAcc = RTrg; RAdderStart = RTrg; MainR = oMainR; AuxR = oAuxR; } else { MainR = (Dry * ((s32)RAcc>>16) + 0x4000) >> 15; AuxR = (Wet * ((s32)RAcc>>16) + 0x4000) >> 15; } } else { if (RAcc > RTrg) { RAcc = RTrg; RAdderStart = RTrg; MainR = oMainR; AuxR = oAuxR; } else { MainR = (Dry * ((s32)RAcc>>16) + 0x4000) >> 15; AuxR = (Wet * ((s32)RAcc>>16) + 0x4000) >> 15; } } //fprintf (dfile, "%04X ", (LAcc>>16)); o1+=(/*(o1*0x7fff)+*/(i1*MainR)+0x4000) >> 15; a1+=(/*(a1*0x7fff)+*/(i1*MainL)+0x4000) >> 15; /* o1=((s64)(((s64)o1*0xfffe)+((s64)i1*MainR*2)+0x8000)>>16); a1=((s64)(((s64)a1*0xfffe)+((s64)i1*MainL*2)+0x8000)>>16);*/ o1 = Saturate( o1 ); a1 = Saturate( a1 ); out[ptr^1]=o1; aux1[ptr^1]=a1; if (AuxIncRate) { //a2=((s64)(((s64)a2*0xfffe)+((s64)i1*AuxR*2)+0x8000)>>16); //a3=((s64)(((s64)a3*0xfffe)+((s64)i1*AuxL*2)+0x8000)>>16); a2+=(/*(a2*0x7fff)+*/(i1*AuxR)+0x4000)>>15; a3+=(/*(a3*0x7fff)+*/(i1*AuxL)+0x4000)>>15; a2 = Saturate( a2 ); a3 = Saturate( a3 ); aux2[ptr^1]=a2; aux3[ptr^1]=a3; } ptr++; } } /*LAcc = LAdderEnd; RAcc = RAdderEnd;*/ *(s16 *)(buff + 0) = Wet; // 0-1 *(s16 *)(buff + 2) = Dry; // 2-3 *(s32 *)(buff + 4) = LTrg; // 4-5 *(s32 *)(buff + 6) = RTrg; // 6-7 *(s32 *)(buff + 8) = LRamp; // 8-9 (MixerWorkArea is a 16bit pointer) *(s32 *)(buff + 10) = RRamp; // 10-11 *(s32 *)(buff + 12) = LAdderEnd; // 12-13 *(s32 *)(buff + 14) = RAdderEnd; // 14-15 *(s32 *)(buff + 16) = LAdderStart; // 12-13 *(s32 *)(buff + 18) = RAdderStart; // 14-15 } #if 1 //1->fast, 0->original Azimer //Corn calc two sample (s16) at once so we get to save a u32 void AudioHLEState::Resample( u8 flags, u32 pitch, u32 address ) { #ifdef DAEDALUS_ENABLE_ASSERTS DAEDALUS_ASSERT( (flags & 0x2) == 0, "Resample: unhandled flags %02x", flags ); // Was breakpoint - StrmnNrmn #endif pitch *= 2; s16 * in ( (s16 *)(Buffer) ); u32 * out( (u32 *)(Buffer) ); //Save some bandwith and fuse two sample in one write u32 srcPtr((InBuffer / 2) - 1); u32 dstPtr(OutBuffer / 4); u32 tmp; u32 accumulator; if (flags & 0x1) { in[srcPtr^1] = 0; accumulator = 0; } else { in[(srcPtr)^1] = ((u16 *)rdram)[((address >> 1))^1]; accumulator = *(u16 *)(rdram + address + 10); } for(u32 i = (((Count + 0xF) & 0xFFF0) >> 2); i != 0 ; i-- ) { tmp = (in[srcPtr^1] + FixedPointMul16( in[(srcPtr+1)^1] - in[srcPtr^1], accumulator )) << 16; accumulator += pitch; srcPtr += accumulator >> 16; accumulator &= 0xFFFF; tmp |= (in[srcPtr^1] + FixedPointMul16( in[(srcPtr+1)^1] - in[srcPtr^1], accumulator )) & 0xFFFF; accumulator += pitch; srcPtr += accumulator >> 16; accumulator &= 0xFFFF; out[dstPtr++] = tmp; } ((u16 *)rdram)[((address >> 1))^1] = in[srcPtr^1]; *(u16 *)(rdram + address + 10) = (u16)accumulator; } #else //Needed for Azimers resample alghorithm const u16 ResampleLUT[0x200] = { 0x0C39, 0x66AD, 0x0D46, 0xFFDF, 0x0B39, 0x6696, 0x0E5F, 0xFFD8, 0x0A44, 0x6669, 0x0F83, 0xFFD0, 0x095A, 0x6626, 0x10B4, 0xFFC8, 0x087D, 0x65CD, 0x11F0, 0xFFBF, 0x07AB, 0x655E, 0x1338, 0xFFB6, 0x06E4, 0x64D9, 0x148C, 0xFFAC, 0x0628, 0x643F, 0x15EB, 0xFFA1, 0x0577, 0x638F, 0x1756, 0xFF96, 0x04D1, 0x62CB, 0x18CB, 0xFF8A, 0x0435, 0x61F3, 0x1A4C, 0xFF7E, 0x03A4, 0x6106, 0x1BD7, 0xFF71, 0x031C, 0x6007, 0x1D6C, 0xFF64, 0x029F, 0x5EF5, 0x1F0B, 0xFF56, 0x022A, 0x5DD0, 0x20B3, 0xFF48, 0x01BE, 0x5C9A, 0x2264, 0xFF3A, 0x015B, 0x5B53, 0x241E, 0xFF2C, 0x0101, 0x59FC, 0x25E0, 0xFF1E, 0x00AE, 0x5896, 0x27A9, 0xFF10, 0x0063, 0x5720, 0x297A, 0xFF02, 0x001F, 0x559D, 0x2B50, 0xFEF4, 0xFFE2, 0x540D, 0x2D2C, 0xFEE8, 0xFFAC, 0x5270, 0x2F0D, 0xFEDB, 0xFF7C, 0x50C7, 0x30F3, 0xFED0, 0xFF53, 0x4F14, 0x32DC, 0xFEC6, 0xFF2E, 0x4D57, 0x34C8, 0xFEBD, 0xFF0F, 0x4B91, 0x36B6, 0xFEB6, 0xFEF5, 0x49C2, 0x38A5, 0xFEB0, 0xFEDF, 0x47ED, 0x3A95, 0xFEAC, 0xFECE, 0x4611, 0x3C85, 0xFEAB, 0xFEC0, 0x4430, 0x3E74, 0xFEAC, 0xFEB6, 0x424A, 0x4060, 0xFEAF, 0xFEAF, 0x4060, 0x424A, 0xFEB6, 0xFEAC, 0x3E74, 0x4430, 0xFEC0, 0xFEAB, 0x3C85, 0x4611, 0xFECE, 0xFEAC, 0x3A95, 0x47ED, 0xFEDF, 0xFEB0, 0x38A5, 0x49C2, 0xFEF5, 0xFEB6, 0x36B6, 0x4B91, 0xFF0F, 0xFEBD, 0x34C8, 0x4D57, 0xFF2E, 0xFEC6, 0x32DC, 0x4F14, 0xFF53, 0xFED0, 0x30F3, 0x50C7, 0xFF7C, 0xFEDB, 0x2F0D, 0x5270, 0xFFAC, 0xFEE8, 0x2D2C, 0x540D, 0xFFE2, 0xFEF4, 0x2B50, 0x559D, 0x001F, 0xFF02, 0x297A, 0x5720, 0x0063, 0xFF10, 0x27A9, 0x5896, 0x00AE, 0xFF1E, 0x25E0, 0x59FC, 0x0101, 0xFF2C, 0x241E, 0x5B53, 0x015B, 0xFF3A, 0x2264, 0x5C9A, 0x01BE, 0xFF48, 0x20B3, 0x5DD0, 0x022A, 0xFF56, 0x1F0B, 0x5EF5, 0x029F, 0xFF64, 0x1D6C, 0x6007, 0x031C, 0xFF71, 0x1BD7, 0x6106, 0x03A4, 0xFF7E, 0x1A4C, 0x61F3, 0x0435, 0xFF8A, 0x18CB, 0x62CB, 0x04D1, 0xFF96, 0x1756, 0x638F, 0x0577, 0xFFA1, 0x15EB, 0x643F, 0x0628, 0xFFAC, 0x148C, 0x64D9, 0x06E4, 0xFFB6, 0x1338, 0x655E, 0x07AB, 0xFFBF, 0x11F0, 0x65CD, 0x087D, 0xFFC8, 0x10B4, 0x6626, 0x095A, 0xFFD0, 0x0F83, 0x6669, 0x0A44, 0xFFD8, 0x0E5F, 0x6696, 0x0B39, 0xFFDF, 0x0D46, 0x66AD, 0x0C39 }; void AudioHLEState::Resample( u8 flags, u32 pitch, u32 address ) { bool init( (flags & 0x1) != 0 ); #ifdef DAEDALUS_ENABLE_ASSERTS DAEDALUS_ASSERT( (flags & 0x2) == 0, "Resample: unhandled flags %02x", flags ); // Was breakpoint - StrmnNrmn #endif pitch *= 2; s16 * buffer( (s16 *)(Buffer) ); u32 srcPtr(InBuffer/2); u32 dstPtr(OutBuffer/2); srcPtr -= 4; u32 accumulator; if (init) { for (u32 x=0; x < 4; x++) { buffer[(srcPtr+x)^1] = 0; } accumulator = 0; } else { for (u32 x=0; x < 4; x++) { buffer[(srcPtr+x)^1] = ((u16 *)rdram)[((address/2)+x)^1]; } accumulator = *(u16 *)(rdram+address+10); } u32 loops( ((Count+0xf) & 0xFFF0)/2 ); for(u32 i = 0; i < loops ; ++i ) { u32 location( (accumulator >> 0xa) << 0x3 ); const s16 * lut( (s16 *)(((u8 *)ResampleLUT) + location) ); s32 accum; accum = FixedPointMul15( buffer[(srcPtr+0)^1], lut[0] ); accum += FixedPointMul15( buffer[(srcPtr+1)^1], lut[1] ); accum += FixedPointMul15( buffer[(srcPtr+2)^1], lut[2] ); accum += FixedPointMul15( buffer[(srcPtr+3)^1], lut[3] ); buffer[dstPtr^1] = Saturate(accum); dstPtr++; accumulator += pitch; srcPtr += (accumulator>>16); accumulator&=0xffff; } for (u32 x=0; x < 4; x++) { ((u16 *)rdram)[((address/2)+x)^1] = buffer[(srcPtr+x)^1]; } *(u16 *)(rdram+address+10) = (u16)accumulator; } #endif inline void AudioHLEState::ExtractSamplesScale( s32 * output, u32 inPtr, s32 vscale ) const { u8 icode; // loop of 8, for 8 coded nibbles from 4 bytes which yields 8 s16 pcm values icode = Buffer[(InBuffer+inPtr++)^3]; *output++ = FixedPointMul16( (s16)((icode&0xf0)<< 8), vscale ); *output++ = FixedPointMul16( (s16)((icode&0x0f)<<12), vscale ); icode = Buffer[(InBuffer+inPtr++)^3]; *output++ = FixedPointMul16( (s16)((icode&0xf0)<< 8), vscale ); *output++ = FixedPointMul16( (s16)((icode&0x0f)<<12), vscale ); icode = Buffer[(InBuffer+inPtr++)^3]; *output++ = FixedPointMul16( (s16)((icode&0xf0)<< 8), vscale ); *output++ = FixedPointMul16( (s16)((icode&0x0f)<<12), vscale ); icode = Buffer[(InBuffer+inPtr++)^3]; *output++ = FixedPointMul16( (s16)((icode&0xf0)<< 8), vscale ); *output++ = FixedPointMul16( (s16)((icode&0x0f)<<12), vscale ); } inline void AudioHLEState::ExtractSamples( s32 * output, u32 inPtr ) const { u8 icode; // loop of 8, for 8 coded nibbles from 4 bytes which yields 8 s16 pcm values icode = Buffer[(InBuffer+inPtr++)^3]; *output++ = (s16)((icode&0xf0)<< 8); *output++ = (s16)((icode&0x0f)<<12); icode = Buffer[(InBuffer+inPtr++)^3]; *output++ = (s16)((icode&0xf0)<< 8); *output++ = (s16)((icode&0x0f)<<12); icode = Buffer[(InBuffer+inPtr++)^3]; *output++ = (s16)((icode&0xf0)<< 8); *output++ = (s16)((icode&0x0f)<<12); icode = Buffer[(InBuffer+inPtr++)^3]; *output++ = (s16)((icode&0xf0)<< 8); *output++ = (s16)((icode&0x0f)<<12); } // // l1/l2 are IN/OUT // #if 1 //1->fast, 0->original Azimer //Corn inline void DecodeSamples( s16 * out, s32 & l1, s32 & l2, const s32 * input, const s16 * book1, const s16 * book2 ) { s32 a[8]; a[0]= (s32)book1[0]*l1; a[0]+=(s32)book2[0]*l2; a[0]+=input[0]*2048; a[1] =(s32)book1[1]*l1; a[1]+=(s32)book2[1]*l2; a[1]+=(s32)book2[0]*input[0]; a[1]+=input[1]*2048; a[2] =(s32)book1[2]*l1; a[2]+=(s32)book2[2]*l2; a[2]+=(s32)book2[1]*input[0]; a[2]+=(s32)book2[0]*input[1]; a[2]+=input[2]*2048; a[3] =(s32)book1[3]*l1; a[3]+=(s32)book2[3]*l2; a[3]+=(s32)book2[2]*input[0]; a[3]+=(s32)book2[1]*input[1]; a[3]+=(s32)book2[0]*input[2]; a[3]+=input[3]*2048; a[4] =(s32)book1[4]*l1; a[4]+=(s32)book2[4]*l2; a[4]+=(s32)book2[3]*input[0]; a[4]+=(s32)book2[2]*input[1]; a[4]+=(s32)book2[1]*input[2]; a[4]+=(s32)book2[0]*input[3]; a[4]+=input[4]*2048; a[5] =(s32)book1[5]*l1; a[5]+=(s32)book2[5]*l2; a[5]+=(s32)book2[4]*input[0]; a[5]+=(s32)book2[3]*input[1]; a[5]+=(s32)book2[2]*input[2]; a[5]+=(s32)book2[1]*input[3]; a[5]+=(s32)book2[0]*input[4]; a[5]+=input[5]*2048; a[6] =(s32)book1[6]*l1; a[6]+=(s32)book2[6]*l2; a[6]+=(s32)book2[5]*input[0]; a[6]+=(s32)book2[4]*input[1]; a[6]+=(s32)book2[3]*input[2]; a[6]+=(s32)book2[2]*input[3]; a[6]+=(s32)book2[1]*input[4]; a[6]+=(s32)book2[0]*input[5]; a[6]+=input[6]*2048; a[7] =(s32)book1[7]*l1; a[7]+=(s32)book2[7]*l2; a[7]+=(s32)book2[6]*input[0]; a[7]+=(s32)book2[5]*input[1]; a[7]+=(s32)book2[4]*input[2]; a[7]+=(s32)book2[3]*input[3]; a[7]+=(s32)book2[2]*input[4]; a[7]+=(s32)book2[1]*input[5]; a[7]+=(s32)book2[0]*input[6]; a[7]+=input[7]*2048; *out++ = Saturate( a[1] >> 11 ); *out++ = Saturate( a[0] >> 11 ); *out++ = Saturate( a[3] >> 11 ); *out++ = Saturate( a[2] >> 11 ); *out++ = Saturate( a[5] >> 11 ); *out++ = Saturate( a[4] >> 11 ); *out++ = l2 = Saturate( a[7] >> 11 ); *out++ = l1 = Saturate( a[6] >> 11 ); } #else inline void DecodeSamples( s16 * out, s32 & l1, s32 & l2, const s32 * input, const s16 * book1, const s16 * book2 ) { s32 a[8]; a[0]= (s32)book1[0]*l1; a[0]+=(s32)book2[0]*l2; a[0]+=input[0]*2048; a[1] =(s32)book1[1]*l1; a[1]+=(s32)book2[1]*l2; a[1]+=(s32)book2[0]*input[0]; a[1]+=input[1]*2048; a[2] =(s32)book1[2]*l1; a[2]+=(s32)book2[2]*l2; a[2]+=(s32)book2[1]*input[0]; a[2]+=(s32)book2[0]*input[1]; a[2]+=input[2]*2048; a[3] =(s32)book1[3]*l1; a[3]+=(s32)book2[3]*l2; a[3]+=(s32)book2[2]*input[0]; a[3]+=(s32)book2[1]*input[1]; a[3]+=(s32)book2[0]*input[2]; a[3]+=input[3]*2048; a[4] =(s32)book1[4]*l1; a[4]+=(s32)book2[4]*l2; a[4]+=(s32)book2[3]*input[0]; a[4]+=(s32)book2[2]*input[1]; a[4]+=(s32)book2[1]*input[2]; a[4]+=(s32)book2[0]*input[3]; a[4]+=input[4]*2048; a[5] =(s32)book1[5]*l1; a[5]+=(s32)book2[5]*l2; a[5]+=(s32)book2[4]*input[0]; a[5]+=(s32)book2[3]*input[1]; a[5]+=(s32)book2[2]*input[2]; a[5]+=(s32)book2[1]*input[3]; a[5]+=(s32)book2[0]*input[4]; a[5]+=input[5]*2048; a[6] =(s32)book1[6]*l1; a[6]+=(s32)book2[6]*l2; a[6]+=(s32)book2[5]*input[0]; a[6]+=(s32)book2[4]*input[1]; a[6]+=(s32)book2[3]*input[2]; a[6]+=(s32)book2[2]*input[3]; a[6]+=(s32)book2[1]*input[4]; a[6]+=(s32)book2[0]*input[5]; a[6]+=input[6]*2048; a[7] =(s32)book1[7]*l1; a[7]+=(s32)book2[7]*l2; a[7]+=(s32)book2[6]*input[0]; a[7]+=(s32)book2[5]*input[1]; a[7]+=(s32)book2[4]*input[2]; a[7]+=(s32)book2[3]*input[3]; a[7]+=(s32)book2[2]*input[4]; a[7]+=(s32)book2[1]*input[5]; a[7]+=(s32)book2[0]*input[6]; a[7]+=input[7]*2048; s16 r[8]; for(u32 j=0;j<8;j++) { u32 idx( j^1 ); r[idx] = Saturate( a[idx] >> 11 ); *(out++) = r[idx]; } l1=r[6]; l2=r[7]; } #endif void AudioHLEState::ADPCMDecode( u8 flags, u32 address ) { bool init( (flags&0x1) != 0 ); bool loop( (flags&0x2) != 0 ); u16 inPtr=0; s16 *out=(s16 *)(Buffer+OutBuffer); if(init) { memset( out, 0, 32 ); } else { u32 addr( loop ? LoopVal : address ); memmove( out, &rdram[addr], 32 ); } s32 l1=out[15]; s32 l2=out[14]; out+=16; s32 inp1[8]; s32 inp2[8]; s32 count = (s16)Count; // XXXX why convert this to signed? while(count>0) { // the first iteration through, these values are // either 0 in the case of A_INIT, from a special // area of memory in the case of A_LOOP or just // the values we calculated the last time u8 code=Buffer[(InBuffer+inPtr)^3]; u32 index=code&0xf; // index into the adpcm code table s16 * book1=(s16 *)&ADPCMTable[index<<4]; s16 * book2=book1+8; code>>=4; // upper nibble is scale inPtr++; // coded adpcm data lies next if( code < 12 ) { s32 vscale=(0x8000>>((12-code)-1)); // very strange. 0x8000 would be .5 in 16:16 format // so this appears to be a fractional scale based // on the 12 based inverse of the scale value. note // that this could be negative, in which case we do // not use the calculated vscale value... see the // if(code>12) check below ExtractSamplesScale( inp1, inPtr + 0, vscale ); ExtractSamplesScale( inp2, inPtr + 4, vscale ); } else { ExtractSamples( inp1, inPtr + 0 ); ExtractSamples( inp2, inPtr + 4 ); } DecodeSamples( out + 0, l1, l2, inp1, book1, book2 ); DecodeSamples( out + 8, l1, l2, inp2, book1, book2 ); inPtr += 8; out += 16; count-=32; } out-=16; memmove(&rdram[address],out,32); } void AudioHLEState::LoadBuffer( u32 address ) { LoadBuffer( InBuffer, address, Count ); } void AudioHLEState::SaveBuffer( u32 address ) { SaveBuffer( address, OutBuffer, Count ); } void AudioHLEState::LoadBuffer( u16 dram_dst, u32 ram_src, u16 count ) { if( count > 0 ) { // XXXX Masks look suspicious - trying to get around endian issues? memmove( Buffer+(dram_dst & 0xFFFC), rdram+(ram_src&0xfffffc), (count+3) & 0xFFFC ); } } void AudioHLEState::SaveBuffer( u32 ram_dst, u16 dmem_src, u16 count ) { if( count > 0 ) { // XXXX Masks look suspicious - trying to get around endian issues? memmove( rdram+(ram_dst & 0xfffffc), Buffer+(dmem_src & 0xFFFC), (count+3) & 0xFFFC); } } /* void AudioHLEState::SetSegment( u8 segment, u32 address ) { DAEDALUS_ASSERT( segment < 16, "Invalid segment" ); Segments[segment&0xf] = address; } */ void AudioHLEState::SetLoop( u32 loopval ) { LoopVal = loopval; //VolTrgLeft = (s16)(LoopVal>>16); // m_LeftVol //VolRampLeft = (s16)(LoopVal); // m_LeftVolTarget } void AudioHLEState::SetBuffer( u8 flags, u16 in, u16 out, u16 count ) { if (flags & 0x8) { // A_AUX - Auxillary Sound Buffer Settings AuxA = in; AuxC = out; AuxE = count; } else { // A_MAIN - Main Sound Buffer Settings InBuffer = in; OutBuffer = out; Count = count; } } void AudioHLEState::DmemMove( u32 dst, u32 src, u16 count ) { count = (count + 3) & 0xfffc; #if 1 //1->fast, 0->slow //Can't use fast_memcpy_swizzle, since this code can run on the ME, and VFPU is not accessible memcpy_swizzle(Buffer + dst, Buffer + src, count); #else for (u32 i = 0; i < count; i++) { *(u8 *)(Buffer+((i+dst)^3)) = *(u8 *)(Buffer+((i+src)^3)); } #endif } void AudioHLEState::LoadADPCM( u32 address, u16 count ) { u32 loops( count / 16 ); const u16 *table( (const u16 *)(rdram + address) ); for (u32 x = 0; x < loops; x++) { ADPCMTable[0x1+(x<<3)] = table[0]; ADPCMTable[0x0+(x<<3)] = table[1]; ADPCMTable[0x3+(x<<3)] = table[2]; ADPCMTable[0x2+(x<<3)] = table[3]; ADPCMTable[0x5+(x<<3)] = table[4]; ADPCMTable[0x4+(x<<3)] = table[5]; ADPCMTable[0x7+(x<<3)] = table[6]; ADPCMTable[0x6+(x<<3)] = table[7]; table += 8; } } void AudioHLEState::Interleave( u16 outaddr, u16 laddr, u16 raddr, u16 count ) { u32 * out = (u32 *)(Buffer + outaddr); //Save some bandwith also corrected left and right//Corn const u16 * inr = (const u16 *)(Buffer + raddr); const u16 * inl = (const u16 *)(Buffer + laddr); for( u32 x = (count >> 2); x != 0; x-- ) { const u16 right = *inr++; const u16 left = *inl++; *out++ = (*inr++ << 16) | *inl++; *out++ = (right << 16) | left; } } void AudioHLEState::Interleave( u16 laddr, u16 raddr ) { Interleave( OutBuffer, laddr, raddr, Count ); } void AudioHLEState::Mixer( u16 dmemout, u16 dmemin, s32 gain, u16 count ) { #if 1 //1->fast, 0->safe/slow //Corn // Make sure we are on even address (YOSHI) s16* in( (s16 *)(Buffer + dmemin) ); s16* out( (s16 *)(Buffer + dmemout) ); for( u32 x = count >> 1; x != 0; x-- ) { *out = Saturate( FixedPointMul15( *in++, gain ) + s32( *out ) ); out++; } #else for( u32 x=0; x < count; x+=2 ) { s16 in( *(s16 *)(Buffer+(dmemin+x)) ); s16 out( *(s16 *)(Buffer+(dmemout+x)) ); *(s16 *)(Buffer+((dmemout+x) & (N64_AUDIO_BUFF - 2)) ) = Saturate( FixedPointMul15( in, gain ) + s32( out ) ); } #endif } void AudioHLEState::Deinterleave( u16 outaddr, u16 inaddr, u16 count ) { while( count-- ) { *(s16 *)(Buffer+(outaddr^2)) = *(s16 *)(Buffer+(inaddr^2)); outaddr += 2; inaddr += 4; } } void AudioHLEState::Mixer( u16 dmemout, u16 dmemin, s32 gain ) { Mixer( dmemout, dmemin, gain, Count ); }