928d660a67
Change-Id: I124cf59c641c2e161cc147b031d9bef5ef773dfb
251 lines
7.3 KiB
C
251 lines
7.3 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2006 Thom Johansen
|
|
* Copyright (C) 2012 Michael Sevakis
|
|
*
|
|
* 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 "rbcodecconfig.h"
|
|
#include "sound.h"
|
|
#include "fixedpoint.h"
|
|
#include "fracmul.h"
|
|
#include "dsp_proc_entry.h"
|
|
#include "channel_mode.h"
|
|
#include <string.h>
|
|
|
|
#if 0
|
|
/* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for
|
|
* completeness. */
|
|
void channel_mode_proc_stereo(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p);
|
|
#endif
|
|
void channel_mode_proc_mono(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p);
|
|
void channel_mode_proc_mono_left(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p);
|
|
void channel_mode_proc_mono_right(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p);
|
|
void channel_mode_proc_custom(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p);
|
|
void channel_mode_proc_karaoke(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p);
|
|
|
|
static struct channel_mode_data
|
|
{
|
|
long sw_gain; /* 00h: for mode: custom */
|
|
long sw_cross; /* 04h: for mode: custom */
|
|
int mode;
|
|
} channel_mode_data =
|
|
{
|
|
.sw_gain = 0,
|
|
.sw_cross = 0,
|
|
.mode = SOUND_CHAN_STEREO
|
|
};
|
|
|
|
#if 0
|
|
/* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for
|
|
* completeness. */
|
|
void channel_mode_proc_stereo(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p)
|
|
{
|
|
/* The channels are each just themselves */
|
|
(void)this; (void)buf_p;
|
|
}
|
|
#endif
|
|
|
|
#if !defined(CPU_COLDFIRE) && !defined(CPU_ARM)
|
|
/* Unoptimized routines */
|
|
void channel_mode_proc_mono(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p)
|
|
{
|
|
struct dsp_buffer *buf = *buf_p;
|
|
int32_t *sl = buf->p32[0];
|
|
int32_t *sr = buf->p32[1];
|
|
int count = buf->remcount;
|
|
|
|
do
|
|
{
|
|
int32_t lr = *sl / 2 + *sr / 2;
|
|
*sl++ = lr;
|
|
*sr++ = lr;
|
|
}
|
|
while (--count > 0);
|
|
|
|
(void)this;
|
|
}
|
|
|
|
void channel_mode_proc_custom(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p)
|
|
{
|
|
struct channel_mode_data *data = (void *)this->data;
|
|
struct dsp_buffer *buf = *buf_p;
|
|
|
|
int32_t *sl = buf->p32[0];
|
|
int32_t *sr = buf->p32[1];
|
|
int count = buf->remcount;
|
|
|
|
const int32_t gain = data->sw_gain;
|
|
const int32_t cross = data->sw_cross;
|
|
|
|
do
|
|
{
|
|
int32_t l = *sl;
|
|
int32_t r = *sr;
|
|
*sl++ = FRACMUL(l, gain) + FRACMUL(r, cross);
|
|
*sr++ = FRACMUL(r, gain) + FRACMUL(l, cross);
|
|
}
|
|
while (--count > 0);
|
|
}
|
|
|
|
void channel_mode_proc_karaoke(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p)
|
|
{
|
|
struct dsp_buffer *buf = *buf_p;
|
|
int32_t *sl = buf->p32[0];
|
|
int32_t *sr = buf->p32[1];
|
|
int count = buf->remcount;
|
|
|
|
do
|
|
{
|
|
int32_t ch = *sl / 2 - *sr / 2;
|
|
*sl++ = ch;
|
|
*sr++ = -ch;
|
|
}
|
|
while (--count > 0);
|
|
|
|
(void)this;
|
|
}
|
|
#endif /* CPU */
|
|
|
|
void channel_mode_proc_mono_left(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p)
|
|
{
|
|
/* Just copy over the other channel */
|
|
struct dsp_buffer *buf = *buf_p;
|
|
memcpy(buf->p32[1], buf->p32[0], buf->remcount * sizeof (int32_t));
|
|
(void)this;
|
|
}
|
|
|
|
void channel_mode_proc_mono_right(struct dsp_proc_entry *this,
|
|
struct dsp_buffer **buf_p)
|
|
{
|
|
/* Just copy over the other channel */
|
|
struct dsp_buffer *buf = *buf_p;
|
|
memcpy(buf->p32[0], buf->p32[1], buf->remcount * sizeof (int32_t));
|
|
(void)this;
|
|
}
|
|
|
|
void channel_mode_set_config(int value)
|
|
{
|
|
if (value < 0 || value >= SOUND_CHAN_NUM_MODES)
|
|
value = SOUND_CHAN_STEREO; /* Out of range */
|
|
|
|
if (value == channel_mode_data.mode)
|
|
return;
|
|
|
|
channel_mode_data.mode = value;
|
|
dsp_proc_enable(dsp_get_config(CODEC_IDX_AUDIO), DSP_PROC_CHANNEL_MODE,
|
|
value != SOUND_CHAN_STEREO);
|
|
}
|
|
|
|
void channel_mode_custom_set_width(int value)
|
|
{
|
|
long width, straight, cross;
|
|
|
|
width = value * 0x7fffff / 100;
|
|
|
|
if (value <= 100)
|
|
{
|
|
straight = (0x7fffff + width) / 2;
|
|
cross = straight - width;
|
|
}
|
|
else
|
|
{
|
|
/* straight = (1 + width) / (2 * width) */
|
|
straight = fp_div(0x7fffff + width, width, 22);
|
|
cross = straight - 0x7fffff;
|
|
}
|
|
|
|
channel_mode_data.sw_gain = straight << 8;
|
|
channel_mode_data.sw_cross = cross << 8;
|
|
}
|
|
|
|
static void update_process_fn(struct dsp_proc_entry *this)
|
|
{
|
|
static const dsp_proc_fn_type fns[SOUND_CHAN_NUM_MODES] =
|
|
{
|
|
[SOUND_CHAN_STEREO] = NULL,
|
|
[SOUND_CHAN_MONO] = channel_mode_proc_mono,
|
|
[SOUND_CHAN_CUSTOM] = channel_mode_proc_custom,
|
|
[SOUND_CHAN_MONO_LEFT] = channel_mode_proc_mono_left,
|
|
[SOUND_CHAN_MONO_RIGHT] = channel_mode_proc_mono_right,
|
|
[SOUND_CHAN_KARAOKE] = channel_mode_proc_karaoke,
|
|
};
|
|
|
|
this->process = fns[((struct channel_mode_data *)this->data)->mode];
|
|
}
|
|
|
|
/* Handle format changes and verify the format compatibility */
|
|
static intptr_t channel_mode_new_format(struct dsp_proc_entry *this,
|
|
struct dsp_config *dsp,
|
|
struct sample_format *format)
|
|
{
|
|
DSP_PRINT_FORMAT(DSP_PROC_CHANNEL_MODE, *format);
|
|
|
|
bool active = format->num_channels >= 2;
|
|
dsp_proc_activate(dsp, DSP_PROC_CHANNEL_MODE, active);
|
|
|
|
if (active)
|
|
return PROC_NEW_FORMAT_OK;
|
|
|
|
/* Can't do this. Sleep until next change. */
|
|
DEBUGF(" DSP_PROC_CHANNEL_MODE- deactivated\n");
|
|
return PROC_NEW_FORMAT_DEACTIVATED;
|
|
|
|
(void)this;
|
|
}
|
|
|
|
/* DSP message hook */
|
|
static intptr_t channel_mode_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:
|
|
if (value == 0)
|
|
this->data = (intptr_t)&channel_mode_data;
|
|
|
|
update_process_fn(this);
|
|
break;
|
|
|
|
case DSP_PROC_NEW_FORMAT:
|
|
retval = channel_mode_new_format(this, dsp,
|
|
(struct sample_format *)value);
|
|
break;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* Database entry */
|
|
DSP_PROC_DB_ENTRY(
|
|
CHANNEL_MODE,
|
|
channel_mode_configure);
|