cog/Frameworks/lazyusf2/lazyusf2/rsp_hle/alist.c

1048 lines
32 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus-rsp-hle - alist.c *
* Mupen64Plus homepage: https://mupen64plus.org/ *
* Copyright (C) 2014 Bobby Smiles *
* Copyright (C) 2009 Richard Goedeken *
* Copyright (C) 2002 Hacktarux *
* *
* 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "alist.h"
#include "arithmetics.h"
#include "audio.h"
#include "hle_external.h"
#include "hle_internal.h"
#include "memory.h"
struct ramp_t
{
int64_t value;
int64_t step;
int64_t target;
};
/* local functions */
static void swap(int16_t **a, int16_t **b)
{
int16_t* tmp = *b;
*b = *a;
*a = tmp;
}
static int16_t* sample(struct hle_t* hle, unsigned pos)
{
return (int16_t*)hle->alist_buffer + ((pos ^ S) & 0xfff);
}
static uint8_t* alist_u8(struct hle_t* hle, uint16_t dmem)
{
return (uint8_t*)(hle->alist_buffer + ((dmem ^ S8) & 0xfff));
}
static int16_t* alist_s16(struct hle_t* hle, uint16_t dmem)
{
return (int16_t*)(hle->alist_buffer + ((dmem ^ S16) & 0xfff));
}
static void sample_mix(int16_t* dst, int16_t src, int16_t gain)
{
*dst = clamp_s16(*dst + ((src * gain) >> 15));
}
static void alist_envmix_mix(size_t n, int16_t** dst, const int16_t* gains, int16_t src)
{
size_t i;
for(i = 0; i < n; ++i)
sample_mix(dst[i], src, gains[i]);
}
static int16_t ramp_step(struct ramp_t* ramp)
{
bool target_reached;
ramp->value += ramp->step;
target_reached = (ramp->step <= 0)
? (ramp->value <= ramp->target)
: (ramp->value >= ramp->target);
if (target_reached)
{
ramp->value = ramp->target;
ramp->step = 0;
}
return (int16_t)(ramp->value >> 16);
}
/* global functions */
#ifdef DEBUG_INFO
void alist_process(struct hle_t* hle, const acmd_callback_t abi[], unsigned int abi_size, const char* abi_names[])
#else
void alist_process(struct hle_t* hle, const acmd_callback_t abi[], unsigned int abi_size)
#endif
{
uint32_t w1, w2;
unsigned int acmd;
const uint32_t *alist = dram_u32(hle, *dmem_u32(hle, TASK_DATA_PTR));
const uint32_t *const alist_end = alist + (*dmem_u32(hle, TASK_DATA_SIZE) >> 2);
while (alist != alist_end) {
w1 = *(alist++);
w2 = *(alist++);
acmd = (w1 >> 24) & 0x7f;
if (acmd < abi_size)
{
#ifdef DEBUG_INFO
HleVerboseMessage(hle->user_defined, "HLE: %s (%08x %08x)", abi_names[acmd], w1, w2);
#endif
(*abi[acmd])(hle, w1, w2);
}
else
HleWarnMessage(hle->user_defined, "Invalid ABI command %u", acmd);
}
}
uint32_t alist_get_address(struct hle_t* hle, uint32_t so, const uint32_t *segments, size_t n)
{
uint8_t segment = (so >> 24) & 0x3f;
uint32_t offset = (so & 0xffffff);
if (segment >= n) {
HleWarnMessage(hle->user_defined, "Invalid segment %u", segment);
return offset;
}
return segments[segment] + offset;
}
void alist_set_address(struct hle_t* hle, uint32_t so, uint32_t *segments, size_t n)
{
uint8_t segment = (so >> 24) & 0x3f;
uint32_t offset = (so & 0xffffff);
if (segment >= n) {
HleWarnMessage(hle->user_defined, "Invalid segment %u", segment);
return;
}
segments[segment] = offset;
}
void alist_clear(struct hle_t* hle, uint16_t dmem, uint16_t count)
{
while(count != 0) {
*alist_u8(hle, dmem++) = 0;
--count;
}
}
void alist_load(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t count)
{
/* enforce DMA alignment constraints */
dmem &= ~3;
address &= ~7;
count = align(count, 8);
memcpy(hle->alist_buffer + dmem, hle->dram + address, count);
}
void alist_save(struct hle_t* hle, uint16_t dmem, uint32_t address, uint16_t count)
{
/* enforce DMA alignment constraints */
dmem &= ~3;
address &= ~7;
count = align(count, 8);
memcpy(hle->dram + address, hle->alist_buffer + dmem, count);
}
void alist_move(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count)
{
while (count != 0) {
*alist_u8(hle, dmemo++) = *alist_u8(hle, dmemi++);
--count;
}
}
void alist_copy_every_other_sample(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count)
{
while (count != 0) {
*alist_s16(hle, dmemo) = *alist_s16(hle, dmemi);
dmemo += 2;
dmemi += 4;
--count;
}
}
void alist_repeat64(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint8_t count)
{
uint16_t buffer[64];
memcpy(buffer, hle->alist_buffer + dmemi, 128);
while(count != 0) {
memcpy(hle->alist_buffer + dmemo, buffer, 128);
dmemo += 128;
--count;
}
}
void alist_copy_blocks(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t block_size, uint8_t count)
{
int block_left = count;
do
{
int bytes_left = block_size;
do
{
memcpy(hle->alist_buffer + dmemo, hle->alist_buffer + dmemi, 0x20);
bytes_left -= 0x20;
dmemi += 0x20;
dmemo += 0x20;
} while(bytes_left > 0);
--block_left;
} while(block_left > 0);
}
void alist_interleave(struct hle_t* hle, uint16_t dmemo, uint16_t left, uint16_t right, uint16_t count)
{
uint16_t *dst = (uint16_t*)(hle->alist_buffer + dmemo);
const uint16_t *srcL = (uint16_t*)(hle->alist_buffer + left);
const uint16_t *srcR = (uint16_t*)(hle->alist_buffer + right);
count >>= 2;
while(count != 0) {
uint16_t l1 = *(srcL++);
uint16_t l2 = *(srcL++);
uint16_t r1 = *(srcR++);
uint16_t r2 = *(srcR++);
#if M64P_BIG_ENDIAN
*(dst++) = l1;
*(dst++) = r1;
*(dst++) = l2;
*(dst++) = r2;
#else
*(dst++) = r2;
*(dst++) = l2;
*(dst++) = r1;
*(dst++) = l1;
#endif
--count;
}
}
void alist_envmix_exp(
struct hle_t* hle,
bool init,
bool aux,
uint16_t dmem_dl, uint16_t dmem_dr,
uint16_t dmem_wl, uint16_t dmem_wr,
uint16_t dmemi, uint16_t count,
int16_t dry, int16_t wet,
const int16_t *vol,
const int16_t *target,
const int32_t *rate,
uint32_t address)
{
size_t n = (aux) ? 4 : 2;
const int16_t* const in = (int16_t*)(hle->alist_buffer + dmemi);
int16_t* const dl = (int16_t*)(hle->alist_buffer + dmem_dl);
int16_t* const dr = (int16_t*)(hle->alist_buffer + dmem_dr);
int16_t* const wl = (int16_t*)(hle->alist_buffer + dmem_wl);
int16_t* const wr = (int16_t*)(hle->alist_buffer + dmem_wr);
struct ramp_t ramps[2];
int32_t exp_seq[2];
int32_t exp_rates[2];
uint32_t ptr = 0;
int x, y;
short save_buffer[40];
memcpy((uint8_t *)save_buffer, (hle->dram + address), sizeof(save_buffer));
if (init) {
ramps[0].value = (vol[0] << 16);
ramps[1].value = (vol[1] << 16);
ramps[0].target = (target[0] << 16);
ramps[1].target = (target[1] << 16);
exp_rates[0] = rate[0];
exp_rates[1] = rate[1];
exp_seq[0] = (vol[0] * rate[0]);
exp_seq[1] = (vol[1] * rate[1]);
} else {
wet = *(int16_t *)(save_buffer + 0); /* 0-1 */
dry = *(int16_t *)(save_buffer + 2); /* 2-3 */
ramps[0].target = *(int32_t *)(save_buffer + 4); /* 4-5 */
ramps[1].target = *(int32_t *)(save_buffer + 6); /* 6-7 */
exp_rates[0] = *(int32_t *)(save_buffer + 8); /* 8-9 (save_buffer is a 16bit pointer) */
exp_rates[1] = *(int32_t *)(save_buffer + 10); /* 10-11 */
exp_seq[0] = *(int32_t *)(save_buffer + 12); /* 12-13 */
exp_seq[1] = *(int32_t *)(save_buffer + 14); /* 14-15 */
ramps[0].value = *(int32_t *)(save_buffer + 16); /* 12-13 */
ramps[1].value = *(int32_t *)(save_buffer + 18); /* 14-15 */
}
/* init which ensure ramp.step != 0 iff ramp.value == ramp.target */
ramps[0].step = ramps[0].target - ramps[0].value;
ramps[1].step = ramps[1].target - ramps[1].value;
for (y = 0; y < count; y += 16) {
if (ramps[0].step != 0)
{
exp_seq[0] = ((int64_t)exp_seq[0]*(int64_t)exp_rates[0]) >> 16;
ramps[0].step = (exp_seq[0] - ramps[0].value) >> 3;
}
if (ramps[1].step != 0)
{
exp_seq[1] = ((int64_t)exp_seq[1]*(int64_t)exp_rates[1]) >> 16;
ramps[1].step = (exp_seq[1] - ramps[1].value) >> 3;
}
for (x = 0; x < 8; ++x) {
int16_t gains[4];
int16_t* buffers[4];
int16_t l_vol = ramp_step(&ramps[0]);
int16_t r_vol = ramp_step(&ramps[1]);
buffers[0] = dl + (ptr^S);
buffers[1] = dr + (ptr^S);
buffers[2] = wl + (ptr^S);
buffers[3] = wr + (ptr^S);
gains[0] = clamp_s16((l_vol * dry + 0x4000) >> 15);
gains[1] = clamp_s16((r_vol * dry + 0x4000) >> 15);
gains[2] = clamp_s16((l_vol * wet + 0x4000) >> 15);
gains[3] = clamp_s16((r_vol * wet + 0x4000) >> 15);
alist_envmix_mix(n, buffers, gains, in[ptr^S]);
++ptr;
}
}
*(int16_t *)(save_buffer + 0) = wet; /* 0-1 */
*(int16_t *)(save_buffer + 2) = dry; /* 2-3 */
*(int32_t *)(save_buffer + 4) = (int32_t)ramps[0].target; /* 4-5 */
*(int32_t *)(save_buffer + 6) = (int32_t)ramps[1].target; /* 6-7 */
*(int32_t *)(save_buffer + 8) = exp_rates[0]; /* 8-9 (save_buffer is a 16bit pointer) */
*(int32_t *)(save_buffer + 10) = exp_rates[1]; /* 10-11 */
*(int32_t *)(save_buffer + 12) = exp_seq[0]; /* 12-13 */
*(int32_t *)(save_buffer + 14) = exp_seq[1]; /* 14-15 */
*(int32_t *)(save_buffer + 16) = (int32_t)ramps[0].value; /* 12-13 */
*(int32_t *)(save_buffer + 18) = (int32_t)ramps[1].value; /* 14-15 */
memcpy(hle->dram + address, (uint8_t *)save_buffer, sizeof(save_buffer));
}
void alist_envmix_ge(
struct hle_t* hle,
bool init,
bool aux,
uint16_t dmem_dl, uint16_t dmem_dr,
uint16_t dmem_wl, uint16_t dmem_wr,
uint16_t dmemi, uint16_t count,
int16_t dry, int16_t wet,
const int16_t *vol,
const int16_t *target,
const int32_t *rate,
uint32_t address)
{
unsigned k;
size_t n = (aux) ? 4 : 2;
const int16_t* const in = (int16_t*)(hle->alist_buffer + dmemi);
int16_t* const dl = (int16_t*)(hle->alist_buffer + dmem_dl);
int16_t* const dr = (int16_t*)(hle->alist_buffer + dmem_dr);
int16_t* const wl = (int16_t*)(hle->alist_buffer + dmem_wl);
int16_t* const wr = (int16_t*)(hle->alist_buffer + dmem_wr);
struct ramp_t ramps[2];
short save_buffer[40];
memcpy((uint8_t *)save_buffer, (hle->dram + address), 80);
if (init) {
ramps[0].value = (vol[0] << 16);
ramps[1].value = (vol[1] << 16);
ramps[0].target = (target[0] << 16);
ramps[1].target = (target[1] << 16);
ramps[0].step = rate[0] / 8;
ramps[1].step = rate[1] / 8;
} else {
wet = *(int16_t *)(save_buffer + 0); /* 0-1 */
dry = *(int16_t *)(save_buffer + 2); /* 2-3 */
ramps[0].target = *(int32_t *)(save_buffer + 4); /* 4-5 */
ramps[1].target = *(int32_t *)(save_buffer + 6); /* 6-7 */
ramps[0].step = *(int32_t *)(save_buffer + 8); /* 8-9 (save_buffer is a 16bit pointer) */
ramps[1].step = *(int32_t *)(save_buffer + 10); /* 10-11 */
/* *(int32_t *)(save_buffer + 12);*/ /* 12-13 */
/* *(int32_t *)(save_buffer + 14);*/ /* 14-15 */
ramps[0].value = *(int32_t *)(save_buffer + 16); /* 12-13 */
ramps[1].value = *(int32_t *)(save_buffer + 18); /* 14-15 */
}
count >>= 1;
for (k = 0; k < count; ++k) {
int16_t gains[4];
int16_t* buffers[4];
int16_t l_vol = ramp_step(&ramps[0]);
int16_t r_vol = ramp_step(&ramps[1]);
buffers[0] = dl + (k^S);
buffers[1] = dr + (k^S);
buffers[2] = wl + (k^S);
buffers[3] = wr + (k^S);
gains[0] = clamp_s16((l_vol * dry + 0x4000) >> 15);
gains[1] = clamp_s16((r_vol * dry + 0x4000) >> 15);
gains[2] = clamp_s16((l_vol * wet + 0x4000) >> 15);
gains[3] = clamp_s16((r_vol * wet + 0x4000) >> 15);
alist_envmix_mix(n, buffers, gains, in[k^S]);
}
*(int16_t *)(save_buffer + 0) = wet; /* 0-1 */
*(int16_t *)(save_buffer + 2) = dry; /* 2-3 */
*(int32_t *)(save_buffer + 4) = (int32_t)ramps[0].target; /* 4-5 */
*(int32_t *)(save_buffer + 6) = (int32_t)ramps[1].target; /* 6-7 */
*(int32_t *)(save_buffer + 8) = (int32_t)ramps[0].step; /* 8-9 (save_buffer is a 16bit pointer) */
*(int32_t *)(save_buffer + 10) = (int32_t)ramps[1].step; /* 10-11 */
/**(int32_t *)(save_buffer + 12);*/ /* 12-13 */
/**(int32_t *)(save_buffer + 14);*/ /* 14-15 */
*(int32_t *)(save_buffer + 16) = (int32_t)ramps[0].value; /* 12-13 */
*(int32_t *)(save_buffer + 18) = (int32_t)ramps[1].value; /* 14-15 */
memcpy(hle->dram + address, (uint8_t *)save_buffer, 80);
}
void alist_envmix_lin(
struct hle_t* hle,
bool init,
uint16_t dmem_dl, uint16_t dmem_dr,
uint16_t dmem_wl, uint16_t dmem_wr,
uint16_t dmemi, uint16_t count,
int16_t dry, int16_t wet,
const int16_t *vol,
const int16_t *target,
const int32_t *rate,
uint32_t address)
{
size_t k;
struct ramp_t ramps[2];
int16_t save_buffer[40];
const int16_t * const in = (int16_t*)(hle->alist_buffer + dmemi);
int16_t* const dl = (int16_t*)(hle->alist_buffer + dmem_dl);
int16_t* const dr = (int16_t*)(hle->alist_buffer + dmem_dr);
int16_t* const wl = (int16_t*)(hle->alist_buffer + dmem_wl);
int16_t* const wr = (int16_t*)(hle->alist_buffer + dmem_wr);
memcpy((uint8_t *)save_buffer, hle->dram + address, 80);
if (init) {
ramps[0].step = rate[0] / 8;
ramps[0].value = (vol[0] << 16);
ramps[0].target = (target[0] << 16);
ramps[1].step = rate[1] / 8;
ramps[1].value = (vol[1] << 16);
ramps[1].target = (target[1] << 16);
}
else {
wet = *(int16_t *)(save_buffer + 0); /* 0-1 */
dry = *(int16_t *)(save_buffer + 2); /* 2-3 */
ramps[0].target = *(int16_t *)(save_buffer + 4) << 16; /* 4-5 */
ramps[1].target = *(int16_t *)(save_buffer + 6) << 16; /* 6-7 */
ramps[0].step = *(int32_t *)(save_buffer + 8); /* 8-9 (save_buffer is a 16bit pointer) */
ramps[1].step = *(int32_t *)(save_buffer + 10); /* 10-11 */
ramps[0].value = *(int32_t *)(save_buffer + 16); /* 16-17 */
ramps[1].value = *(int32_t *)(save_buffer + 18); /* 16-17 */
}
count >>= 1;
for(k = 0; k < count; ++k) {
int16_t gains[4];
int16_t* buffers[4];
int16_t l_vol = ramp_step(&ramps[0]);
int16_t r_vol = ramp_step(&ramps[1]);
buffers[0] = dl + (k^S);
buffers[1] = dr + (k^S);
buffers[2] = wl + (k^S);
buffers[3] = wr + (k^S);
gains[0] = clamp_s16((l_vol * dry + 0x4000) >> 15);
gains[1] = clamp_s16((r_vol * dry + 0x4000) >> 15);
gains[2] = clamp_s16((l_vol * wet + 0x4000) >> 15);
gains[3] = clamp_s16((r_vol * wet + 0x4000) >> 15);
alist_envmix_mix(4, buffers, gains, in[k^S]);
}
*(int16_t *)(save_buffer + 0) = wet; /* 0-1 */
*(int16_t *)(save_buffer + 2) = dry; /* 2-3 */
*(int16_t *)(save_buffer + 4) = (int16_t)(ramps[0].target >> 16); /* 4-5 */
*(int16_t *)(save_buffer + 6) = (int16_t)(ramps[1].target >> 16); /* 6-7 */
*(int32_t *)(save_buffer + 8) = (int32_t)ramps[0].step; /* 8-9 (save_buffer is a 16bit pointer) */
*(int32_t *)(save_buffer + 10) = (int32_t)ramps[1].step; /* 10-11 */
*(int32_t *)(save_buffer + 16) = (int32_t)ramps[0].value; /* 16-17 */
*(int32_t *)(save_buffer + 18) = (int32_t)ramps[1].value; /* 18-19 */
memcpy(hle->dram + address, (uint8_t *)save_buffer, 80);
}
void alist_envmix_nead(
struct hle_t* hle,
bool swap_wet_LR,
uint16_t dmem_dl,
uint16_t dmem_dr,
uint16_t dmem_wl,
uint16_t dmem_wr,
uint16_t dmemi,
unsigned count,
uint16_t *env_values,
uint16_t *env_steps,
const int16_t *xors)
{
int16_t *in = (int16_t*)(hle->alist_buffer + dmemi);
int16_t *dl = (int16_t*)(hle->alist_buffer + dmem_dl);
int16_t *dr = (int16_t*)(hle->alist_buffer + dmem_dr);
int16_t *wl = (int16_t*)(hle->alist_buffer + dmem_wl);
int16_t *wr = (int16_t*)(hle->alist_buffer + dmem_wr);
/* make sure count is a multiple of 8 */
count = align(count, 8);
if (swap_wet_LR)
swap(&wl, &wr);
while (count != 0) {
size_t i;
for(i = 0; i < 8; ++i) {
int16_t l = (((int32_t)in[i^S] * (uint32_t)env_values[0]) >> 16) ^ xors[0];
int16_t r = (((int32_t)in[i^S] * (uint32_t)env_values[1]) >> 16) ^ xors[1];
int16_t l2 = (((int32_t)l * (uint32_t)env_values[2]) >> 16) ^ xors[2];
int16_t r2 = (((int32_t)r * (uint32_t)env_values[2]) >> 16) ^ xors[3];
dl[i^S] = clamp_s16(dl[i^S] + l);
dr[i^S] = clamp_s16(dr[i^S] + r);
wl[i^S] = clamp_s16(wl[i^S] + l2);
wr[i^S] = clamp_s16(wr[i^S] + r2);
}
env_values[0] += env_steps[0];
env_values[1] += env_steps[1];
env_values[2] += env_steps[2];
dl += 8;
dr += 8;
wl += 8;
wr += 8;
in += 8;
count -= 8;
}
}
void alist_mix(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count, int16_t gain)
{
int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo);
const int16_t *src = (int16_t*)(hle->alist_buffer + dmemi);
count >>= 1;
while(count != 0) {
sample_mix(dst, *src, gain);
++dst;
++src;
--count;
}
}
void alist_multQ44(struct hle_t* hle, uint16_t dmem, uint16_t count, int8_t gain)
{
int16_t *dst = (int16_t*)(hle->alist_buffer + dmem);
count >>= 1;
while(count != 0) {
*dst = clamp_s16(*dst * gain >> 4);
++dst;
--count;
}
}
void alist_add(struct hle_t* hle, uint16_t dmemo, uint16_t dmemi, uint16_t count)
{
int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo);
const int16_t *src = (int16_t*)(hle->alist_buffer + dmemi);
count >>= 1;
while(count != 0) {
*dst = clamp_s16(*dst + *src);
++dst;
++src;
--count;
}
}
static void alist_resample_reset(struct hle_t* hle, uint16_t pos, uint32_t* pitch_accu)
{
unsigned k;
for(k = 0; k < 4; ++k)
*sample(hle, pos + k) = 0;
*pitch_accu = 0;
}
static void alist_resample_load(struct hle_t* hle, uint32_t address, uint16_t pos, uint32_t* pitch_accu)
{
*sample(hle, pos + 0) = *dram_u16(hle, address + 0);
*sample(hle, pos + 1) = *dram_u16(hle, address + 2);
*sample(hle, pos + 2) = *dram_u16(hle, address + 4);
*sample(hle, pos + 3) = *dram_u16(hle, address + 6);
*pitch_accu = *dram_u16(hle, address + 8);
}
static void alist_resample_save(struct hle_t* hle, uint32_t address, uint16_t pos, uint32_t pitch_accu)
{
*dram_u16(hle, address + 0) = *sample(hle, pos + 0);
*dram_u16(hle, address + 2) = *sample(hle, pos + 1);
*dram_u16(hle, address + 4) = *sample(hle, pos + 2);
*dram_u16(hle, address + 6) = *sample(hle, pos + 3);
*dram_u16(hle, address + 8) = pitch_accu;
}
void alist_resample(
struct hle_t* hle,
bool init,
bool flag2,
uint16_t dmemo,
uint16_t dmemi,
uint16_t count,
uint32_t pitch, /* Q16.16 */
uint32_t address)
{
uint32_t pitch_accu;
uint16_t ipos = dmemi >> 1;
uint16_t opos = dmemo >> 1;
count >>= 1;
ipos -= 4;
if (flag2)
HleWarnMessage(hle->user_defined, "alist_resample: flag2 is not implemented");
if (init)
alist_resample_reset(hle, ipos, &pitch_accu);
else
alist_resample_load(hle, address, ipos, &pitch_accu);
while (count != 0) {
const int16_t* lut = RESAMPLE_LUT + ((pitch_accu & 0xfc00) >> 8);
*sample(hle, opos++) = clamp_s16( (
(*sample(hle, ipos ) * lut[0]) +
(*sample(hle, ipos + 1) * lut[1]) +
(*sample(hle, ipos + 2) * lut[2]) +
(*sample(hle, ipos + 3) * lut[3]) ) >> 15);
pitch_accu += pitch;
ipos += (pitch_accu >> 16);
pitch_accu &= 0xffff;
--count;
}
alist_resample_save(hle, address, ipos, pitch_accu);
}
void alist_resample_zoh(
struct hle_t* hle,
uint16_t dmemo,
uint16_t dmemi,
uint16_t count,
uint32_t pitch,
uint32_t pitch_accu)
{
uint16_t ipos = dmemi >> 1;
uint16_t opos = dmemo >> 1;
count >>= 1;
while(count != 0) {
*sample(hle, opos++) = *sample(hle, ipos);
pitch_accu += pitch;
ipos += (pitch_accu >> 16);
pitch_accu &= 0xffff;
--count;
}
}
typedef unsigned int (*adpcm_predict_frame_t)(struct hle_t* hle,
int16_t* dst, uint16_t dmemi, unsigned char scale);
static unsigned int adpcm_predict_frame_4bits(struct hle_t* hle,
int16_t* dst, uint16_t dmemi, unsigned char scale)
{
unsigned int i;
unsigned int rshift = (scale < 12) ? 12 - scale : 0;
for(i = 0; i < 8; ++i) {
uint8_t byte = *alist_u8(hle, dmemi++);
*(dst++) = adpcm_predict_sample(byte, 0xf0, 8, rshift);
*(dst++) = adpcm_predict_sample(byte, 0x0f, 12, rshift);
}
return 8;
}
static unsigned int adpcm_predict_frame_2bits(struct hle_t* hle,
int16_t* dst, uint16_t dmemi, unsigned char scale)
{
unsigned int i;
unsigned int rshift = (scale < 14) ? 14 - scale : 0;
for(i = 0; i < 4; ++i) {
uint8_t byte = *alist_u8(hle, dmemi++);
*(dst++) = adpcm_predict_sample(byte, 0xc0, 8, rshift);
*(dst++) = adpcm_predict_sample(byte, 0x30, 10, rshift);
*(dst++) = adpcm_predict_sample(byte, 0x0c, 12, rshift);
*(dst++) = adpcm_predict_sample(byte, 0x03, 14, rshift);
}
return 4;
}
void alist_adpcm(
struct hle_t* hle,
bool init,
bool loop,
bool two_bit_per_sample,
uint16_t dmemo,
uint16_t dmemi,
uint16_t count,
const int16_t* codebook,
uint32_t loop_address,
uint32_t last_frame_address)
{
int16_t last_frame[16];
size_t i;
adpcm_predict_frame_t predict_frame = (two_bit_per_sample)
? adpcm_predict_frame_2bits
: adpcm_predict_frame_4bits;
assert((count & 0x1f) == 0);
if (init)
memset(last_frame, 0, 16*sizeof(last_frame[0]));
else
dram_load_u16(hle, (uint16_t*)last_frame, (loop) ? loop_address : last_frame_address, 16);
for(i = 0; i < 16; ++i, dmemo += 2)
*alist_s16(hle, dmemo) = last_frame[i];
while (count != 0) {
int16_t frame[16];
uint8_t code = *alist_u8(hle, dmemi++);
unsigned char scale = (code & 0xf0) >> 4;
const int16_t* const cb_entry = codebook + ((code & 0xf) << 4);
dmemi += predict_frame(hle, frame, dmemi, scale);
adpcm_compute_residuals(last_frame , frame , cb_entry, last_frame + 14, 8);
adpcm_compute_residuals(last_frame + 8, frame + 8, cb_entry, last_frame + 6 , 8);
for(i = 0; i < 16; ++i, dmemo += 2)
*alist_s16(hle, dmemo) = last_frame[i];
count -= 32;
}
dram_store_u16(hle, (uint16_t*)last_frame, last_frame_address, 16);
}
void alist_filter(
struct hle_t* hle,
uint16_t dmem,
uint16_t count,
uint32_t address,
const uint32_t* lut_address)
{
int x;
int16_t outbuff[0x3c0];
int16_t *outp = outbuff;
int16_t* const lutt6 = (int16_t*)(hle->dram + lut_address[0]);
int16_t* const lutt5 = (int16_t*)(hle->dram + lut_address[1]);
int16_t* in1 = (int16_t*)(hle->dram + address);
int16_t* in2 = (int16_t*)(hle->alist_buffer + dmem);
for (x = 0; x < 8; ++x) {
int32_t v = (lutt5[x] + lutt6[x]) >> 1;
lutt5[x] = lutt6[x] = v;
}
for (x = 0; x < count; x += 16) {
int32_t v[8];
v[1] = in1[0] * lutt6[6];
v[1] += in1[3] * lutt6[7];
v[1] += in1[2] * lutt6[4];
v[1] += in1[5] * lutt6[5];
v[1] += in1[4] * lutt6[2];
v[1] += in1[7] * lutt6[3];
v[1] += in1[6] * lutt6[0];
v[1] += in2[1] * lutt6[1]; /* 1 */
v[0] = in1[3] * lutt6[6];
v[0] += in1[2] * lutt6[7];
v[0] += in1[5] * lutt6[4];
v[0] += in1[4] * lutt6[5];
v[0] += in1[7] * lutt6[2];
v[0] += in1[6] * lutt6[3];
v[0] += in2[1] * lutt6[0];
v[0] += in2[0] * lutt6[1];
v[3] = in1[2] * lutt6[6];
v[3] += in1[5] * lutt6[7];
v[3] += in1[4] * lutt6[4];
v[3] += in1[7] * lutt6[5];
v[3] += in1[6] * lutt6[2];
v[3] += in2[1] * lutt6[3];
v[3] += in2[0] * lutt6[0];
v[3] += in2[3] * lutt6[1];
v[2] = in1[5] * lutt6[6];
v[2] += in1[4] * lutt6[7];
v[2] += in1[7] * lutt6[4];
v[2] += in1[6] * lutt6[5];
v[2] += in2[1] * lutt6[2];
v[2] += in2[0] * lutt6[3];
v[2] += in2[3] * lutt6[0];
v[2] += in2[2] * lutt6[1];
v[5] = in1[4] * lutt6[6];
v[5] += in1[7] * lutt6[7];
v[5] += in1[6] * lutt6[4];
v[5] += in2[1] * lutt6[5];
v[5] += in2[0] * lutt6[2];
v[5] += in2[3] * lutt6[3];
v[5] += in2[2] * lutt6[0];
v[5] += in2[5] * lutt6[1];
v[4] = in1[7] * lutt6[6];
v[4] += in1[6] * lutt6[7];
v[4] += in2[1] * lutt6[4];
v[4] += in2[0] * lutt6[5];
v[4] += in2[3] * lutt6[2];
v[4] += in2[2] * lutt6[3];
v[4] += in2[5] * lutt6[0];
v[4] += in2[4] * lutt6[1];
v[7] = in1[6] * lutt6[6];
v[7] += in2[1] * lutt6[7];
v[7] += in2[0] * lutt6[4];
v[7] += in2[3] * lutt6[5];
v[7] += in2[2] * lutt6[2];
v[7] += in2[5] * lutt6[3];
v[7] += in2[4] * lutt6[0];
v[7] += in2[7] * lutt6[1];
v[6] = in2[1] * lutt6[6];
v[6] += in2[0] * lutt6[7];
v[6] += in2[3] * lutt6[4];
v[6] += in2[2] * lutt6[5];
v[6] += in2[5] * lutt6[2];
v[6] += in2[4] * lutt6[3];
v[6] += in2[7] * lutt6[0];
v[6] += in2[6] * lutt6[1];
outp[1] = ((v[1] + 0x4000) >> 15);
outp[0] = ((v[0] + 0x4000) >> 15);
outp[3] = ((v[3] + 0x4000) >> 15);
outp[2] = ((v[2] + 0x4000) >> 15);
outp[5] = ((v[5] + 0x4000) >> 15);
outp[4] = ((v[4] + 0x4000) >> 15);
outp[7] = ((v[7] + 0x4000) >> 15);
outp[6] = ((v[6] + 0x4000) >> 15);
in1 = in2;
in2 += 8;
outp += 8;
}
memcpy(hle->dram + address, in2 - 8, 16);
memcpy(hle->alist_buffer + dmem, outbuff, count);
}
void alist_polef(
struct hle_t* hle,
bool init,
uint16_t dmemo,
uint16_t dmemi,
uint16_t count,
uint16_t gain,
int16_t* table,
uint32_t address)
{
int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo);
const int16_t* const h1 = table;
int16_t* const h2 = table + 8;
unsigned i;
int16_t l1, l2;
int16_t h2_before[8];
count = align(count, 16);
if (init) {
l1 = 0;
l2 = 0;
}
else {
l1 = *dram_u16(hle, address + 4);
l2 = *dram_u16(hle, address + 6);
}
for(i = 0; i < 8; ++i) {
h2_before[i] = h2[i];
h2[i] = (((int32_t)h2[i] * gain) >> 14);
}
do
{
int16_t frame[8];
for(i = 0; i < 8; ++i, dmemi += 2)
frame[i] = *alist_s16(hle, dmemi);
for(i = 0; i < 8; ++i) {
int32_t accu = frame[i] * gain;
accu += h1[i]*l1 + h2_before[i]*l2 + rdot(i, h2, frame);
dst[i^S] = clamp_s16(accu >> 14);
}
l1 = dst[6^S];
l2 = dst[7^S];
dst += 8;
count -= 16;
} while (count != 0);
dram_store_u32(hle, (uint32_t*)(dst - 4), address, 2);
}
void alist_iirf(
struct hle_t* hle,
bool init,
uint16_t dmemo,
uint16_t dmemi,
uint16_t count,
int16_t* table,
uint32_t address)
{
int16_t *dst = (int16_t*)(hle->alist_buffer + dmemo);
int32_t i, prev;
int16_t frame[8];
int16_t ibuf[4];
uint16_t index = 7;
count = align(count, 16);
if(init)
{
for(i = 0; i < 8; ++i)
frame[i] = 0;
ibuf[1] = 0;
ibuf[2] = 0;
}
else
{
frame[6] = *dram_u16(hle, address + 4);
frame[7] = *dram_u16(hle, address + 6);
ibuf[1] = (int16_t)*dram_u16(hle, address + 8);
ibuf[2] = (int16_t)*dram_u16(hle, address + 10);
}
prev = vmulf(table[9], frame[6]) * 2;
do
{
for(i = 0; i < 8; ++i)
{
int32_t accu;
ibuf[index&3] = *alist_s16(hle, dmemi);
accu = prev + vmulf(table[0], ibuf[index&3]) + vmulf(table[1], ibuf[(index-1)&3]) + vmulf(table[0], ibuf[(index-2)&3]);
accu += vmulf(table[8], frame[index]) * 2;
prev = vmulf(table[9], frame[index]) * 2;
dst[i^S] = frame[i] = accu;
index=(index+1)&7;
dmemi += 2;
}
dst += 8;
count -= 0x10;
} while (count > 0);
dram_store_u16(hle, (uint16_t*)&frame[6], address + 4, 2);
dram_store_u16(hle, (uint16_t*)&ibuf[(index-2)&3], address+8, 1);
dram_store_u16(hle, (uint16_t*)&ibuf[(index-1)&3], address+10, 1);
}
/* Perform a clamped gain, then attenuate it back by an amount */
void alist_overload(struct hle_t* hle, uint16_t dmem, int16_t count, int16_t gain, int16_t attenuation)
{
int16_t accu;
int16_t * sample = (int16_t*)(hle->alist_buffer + dmem);
while (count != 0)
{
accu = clamp_s16(*sample * gain);
*sample = (accu * attenuation) >> 16;
sample++;
count --;
}
}