/* 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 #include #include "Base/Types.h" #include "Utility/MathUtil.h" #include "HLEAudio/HLEAudioInternal.h" #include "HLEAudio/HLEAudioState.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 [[maybe_unused]]) {} void UNKNOWN(AudioHLECommand command [[maybe_unused]]) {} AudioHLEState gAudioHLEState; void AudioHLEState::ClearBuffer(u16 addr, u16 count) { std::fill(Buffer + (addr & 0xfffc), Buffer + ((addr & 0xfffc) + ((count + 3) & 0xfffc)), 0); } 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 MainL = 0 , MainR = 0; s32 AuxL = 0, AuxR = 0; s32 i1 = 0, o1 = 0, a1 = 0, a2 = 0, a3 = 0; u16 AuxIncRate = 1; s16 zero[8] = {}; s32 LVol = 0, RVol = 0 ; s32 LAcc = 0 , RAcc = 0 ; s32 LTrg = 0 , RTrg = 0; s16 Wet = 0, Dry = 0; u32 ptr = 0; s32 LRamp = 0, RRamp = 0; s32 LAdderStart = 0 , RAdderStart = 0 , LAdderEnd = 0, RAdderEnd = 0; s32 oMainL = 0 , oMainR = 0, oAuxL = 0 , oAuxR = 0; s16 *buff = (s16 *)(rdram + address); const auto shift_val = 0x4000; const auto right_shift_val = 15; // 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) + shift_val) >> right_shift_val; oAuxL = (Wet * (LTrg >> 16) + shift_val) >> right_shift_val; oMainR = (Dry * (RTrg >> 16) + shift_val) >> right_shift_val; oAuxR = (Wet * (RTrg >> 16) + shift_val) >> right_shift_val; 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]; std::array a; 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]; // std::array inp1; // std::array inp2; 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); }