rockbox/lib/rbcodec/dsp/surround.c
Aidan MacDonald 1e9ad3ca0d Remove buflib allocation names, part two
Remove allocation names from the buflib API and fix up all callers.

Change-Id: I3df922e258d5f0d711d70e72b56b4ed634fb0f5a
2023-01-13 10:32:54 +00:00

349 lines
9.5 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2014 by Chiwen Chang
*
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "surround.h"
#include "config.h"
#include "fixedpoint.h"
#include "fracmul.h"
#include "settings.h"
#include "dsp_proc_entry.h"
#include "dsp_filter.h"
#include "core_alloc.h"
static int surround_balance = 0;
static bool surround_side_only = false;
static int surround_mix = 100;
static int surround_delay_ms = 0;
/*1 sample ~ 11ns */
#define DLY_1US 90900
#define DLY_5MS ((DLY_1US * 5)/1000) /*(454)*/
/* No longer needed but kept for reference */
/*#define DLY_8MS 727*/
/*#define DLY_10MS 909*/
/*#define DLY_15MS 1363*/
#define DLY_30MS ((DLY_1US * 30)/1000) /*(2727)*/
#define MIN_DLY DLY_5MS
#define MAX_DLY DLY_30MS
#define B0_DLY (MAX_DLY/8 + 1)
#define B2_DLY (MAX_DLY + 1)
#define BB_DLY (MAX_DLY/4 + 1)
#define HH_DLY (MAX_DLY/2 + 1)
#define CL_DLY B2_DLY
/*voice from 300hz - 3400hz ?*/
static int32_t tcoef1,tcoef2,bcoef,hcoef;
static int dly_size = MAX_DLY;
static int cutoff_l = 320;
static int cutoff_h = 3400;
static int b0_r=0,b0_w=0,
b2_r=0,b2_w=0,
bb_r=0,bb_w=0,
hh_r=0,hh_w=0,
cl_r=0,cl_w=0;
static int handle = -1;
#define SURROUND_BUFSIZE ((B0_DLY + B2_DLY + BB_DLY + HH_DLY + CL_DLY)*sizeof (int32_t))
static int surround_buffer_alloc(void)
{
handle = core_alloc(SURROUND_BUFSIZE);
return handle;
}
static void surround_buffer_free(void)
{
if (handle < 0)
return;
core_free(handle);
handle = -1;
}
static void dsp_surround_flush(void)
{
if (handle >= 0)
memset(core_get_data(handle), 0, SURROUND_BUFSIZE);
}
static void surround_update_filter(unsigned int fout)
{
tcoef1 = fp_div(cutoff_l, fout, 31);
tcoef2 = fp_div(cutoff_h, fout, 31);
bcoef = fp_div(cutoff_l / 2, fout, 31);
hcoef = fp_div(cutoff_h * 2, fout, 31);
}
void dsp_surround_set_balance(int var)
{
surround_balance = var;
}
void dsp_surround_side_only(bool var)
{
surround_side_only = var;
}
void dsp_surround_mix(int var)
{
surround_mix = var;
}
void dsp_surround_set_cutoff(int frq_l, int frq_h)
{
if (cutoff_l == frq_l && cutoff_h == frq_h)
return; /* No settings change */
cutoff_l = frq_l;/*fx2*/
cutoff_h = frq_h;/*fx1*/
struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
if (!dsp_proc_enabled(dsp, DSP_PROC_SURROUND))
return;
surround_update_filter(dsp_get_output_frequency(dsp));
}
static void surround_set_delay(int surround_delay_ms)
{
if (handle >= 0)
dsp_surround_flush();
dly_size = ((DLY_1US * surround_delay_ms) /1000);
if (dly_size < MIN_DLY)
dly_size = MIN_DLY;
else if (dly_size > MAX_DLY)
dly_size = MAX_DLY;
}
void dsp_surround_enable(int delay_ms)
{
if (delay_ms == surround_delay_ms)
return; /* No setting change */
surround_delay_ms = delay_ms;
struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
bool was_enabled = dsp_proc_enabled(dsp, DSP_PROC_SURROUND);
bool now_enabled = delay_ms > 0;
if (now_enabled)
surround_set_delay(delay_ms);
if (was_enabled == now_enabled)
return; /* No change in enabled status */
/* If changing status, enable or disable it; if already enabled push
additional DSP_PROC_INIT messages with value = 1 to force-update the
filters */
dsp_proc_enable(dsp, DSP_PROC_SURROUND, now_enabled);
}
static void surround_process(struct dsp_proc_entry *this,
struct dsp_buffer **buf_p)
{
struct dsp_buffer *buf = *buf_p;
int count = buf->remcount;
int dly_shift3 = dly_size/8;
int dly_shift2 = dly_size/4;
int dly_shift1 = dly_size/2;
int dly = dly_size;
int i;
int32_t x;
/*only need to buffer right channel */
static int32_t *b0, *b2, *bb, *hh, *cl;
b0 = core_get_data(handle);
b2 = b0 + B0_DLY;
bb = b2 + B2_DLY;
hh = bb + BB_DLY;
cl = hh + HH_DLY;
for (i = 0; i < count; i++)
{
int32_t mid = buf->p32[0][i] / 2 + buf->p32[1][i] / 2;
int32_t side = buf->p32[0][i] - buf->p32[1][i];
int32_t temp0, temp1;
if (!surround_side_only)
{
/*clone the left channal*/
temp0 = buf->p32[0][i];
/*keep the middle band of right channel*/
temp1 = FRACMUL(buf->p32[1][i], tcoef1) -
FRACMUL(buf->p32[1][i], tcoef2);
}
else /* apply haas to side only*/
{
temp0 = side / 2;
temp1 = FRACMUL(-side, tcoef1) / 2 -
FRACMUL(-side, tcoef2) / 2;
}
/* inverted crossfeed delay (left channel) to make sound wider*/
x = temp1/100 * 35;
temp0 += dequeue(cl, &cl_r, dly);
enqueue(-x, cl, &cl_w, dly);
/* apply 1/8 delay to frequency below fx2 */
x = buf->p32[1][i] - FRACMUL(buf->p32[1][i], tcoef1);
temp1 += dequeue(b0, &b0_r, dly_shift3);
enqueue(x, b0, &b0_w, dly_shift3 );
/* cut frequency below half fx2*/
temp1 = FRACMUL(temp1, bcoef);
/* apply 1/4 delay to frequency below half fx2 */
/* use different delay to fake the sound direction*/
x = buf->p32[1][i] - FRACMUL(buf->p32[1][i], bcoef);
temp1 += dequeue(bb, &bb_r, dly_shift2);
enqueue(x, bb, &bb_w, dly_shift2 );
/* apply full delay to higher band */
x = FRACMUL(buf->p32[1][i], tcoef2);
temp1 += dequeue(b2, &b2_r, dly);
enqueue(x, b2, &b2_w, dly );
/* do the same direction trick again */
temp1 -= FRACMUL(temp1, hcoef);
x = FRACMUL(buf->p32[1][i], hcoef);
temp1 += dequeue(hh, &hh_r, dly_shift1);
enqueue(x, hh, &hh_w, dly_shift1 );
/*balance*/
if (surround_balance > 0 && !surround_side_only)
{
temp0 -= temp0/200 * surround_balance;
temp1 += temp1/200 * surround_balance;
}
else if (surround_balance > 0)
{
temp0 += temp0/200 * surround_balance;
temp1 -= temp1/200 * surround_balance;
}
if (surround_side_only)
{
temp0 += mid;
temp1 += mid;
}
if (surround_mix == 100)
{
buf->p32[0][i] = temp0;
buf->p32[1][i] = temp1;
}
else
{
/*dry wet mix*/
buf->p32[0][i] = buf->p32[0][i]/100 * (100-surround_mix) +
temp0/100 * surround_mix;
buf->p32[1][i] = buf->p32[1][i]/100 * (100-surround_mix) +
temp1/100 * surround_mix;
}
}
(void)this;
}
/* Handle format changes and verify the format compatibility */
static intptr_t surround_new_format(struct dsp_proc_entry *this,
struct dsp_config *dsp,
struct sample_format *format)
{
DSP_PRINT_FORMAT(DSP_PROC_SURROUND, *format);
/* Stereo mode only */
bool was_active = dsp_proc_active(dsp, DSP_PROC_SURROUND);
bool now_active = format->num_channels > 1;
dsp_proc_activate(dsp, DSP_PROC_SURROUND, now_active);
if (now_active)
{
if (!was_active)
dsp_surround_flush(); /* Going online */
return PROC_NEW_FORMAT_OK;
}
/* Can't do this. Sleep until next change. */
DEBUGF(" DSP_PROC_SURROUND- deactivated\n");
return PROC_NEW_FORMAT_DEACTIVATED;
(void)this;
}
/* DSP message hook */
static intptr_t surround_configure(struct dsp_proc_entry *this,
struct dsp_config *dsp,
unsigned int setting,
intptr_t value)
{
intptr_t retval = 0;
switch (setting)
{
case DSP_PROC_INIT:
/* Coming online; was disabled */
retval = surround_buffer_alloc();
if (retval < 0)
break;
this->process = surround_process;
dsp_surround_flush();
/* Wouldn't have been getting frequency updates */
surround_update_filter(dsp_get_output_frequency(dsp));
break;
case DSP_PROC_CLOSE:
/* Being disabled (called also if init fails) */
surround_buffer_free();
break;
case DSP_FLUSH:
/* Discontinuity; clear filters */
dsp_surround_flush();
break;
case DSP_SET_OUT_FREQUENCY:
/* New output frequency */
surround_update_filter(value);
break;
case DSP_PROC_NEW_FORMAT:
/* Source buffer format is changing (also sent when first enabled) */
retval = surround_new_format(this, dsp, (struct sample_format *)value);
break;
}
return retval;
}
/* Database entry */
DSP_PROC_DB_ENTRY(
SURROUND,
surround_configure);