summaryrefslogtreecommitdiffstats
path: root/apps/dsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/dsp.c')
-rw-r--r--apps/dsp.c1573
1 files changed, 0 insertions, 1573 deletions
diff --git a/apps/dsp.c b/apps/dsp.c
deleted file mode 100644
index 4da555747b..0000000000
--- a/apps/dsp.c
+++ /dev/null
@@ -1,1573 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * Open \______ \ ____ ____ | | _\_ |__ _______ ___
- * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- * \/ \/ \/ \/ \/
- * $Id$
- *
- * Copyright (C) 2005 Miika Pekkarinen
- *
- * 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 "config.h"
-#include "system.h"
-#include <sound.h>
-#include "dsp.h"
-#include "dsp-util.h"
-#include "eq.h"
-#include "compressor.h"
-#include "kernel.h"
-#include "settings.h"
-#include "replaygain.h"
-#include "tdspeed.h"
-#include "core_alloc.h"
-#include "fixedpoint.h"
-#include "fracmul.h"
-
-/* Define LOGF_ENABLE to enable logf output in this file */
-/*#define LOGF_ENABLE*/
-#include "logf.h"
-
-/* 16-bit samples are scaled based on these constants. The shift should be
- * no more than 15.
- */
-#define WORD_SHIFT 12
-#define WORD_FRACBITS 27
-
-#define NATIVE_DEPTH 16
-#define SMALL_SAMPLE_BUF_COUNT 128 /* Per channel */
-#define DEFAULT_GAIN 0x01000000
-
-/* enums to index conversion properly with stereo mode and other settings */
-enum
-{
- SAMPLE_INPUT_LE_NATIVE_I_STEREO = STEREO_INTERLEAVED,
- SAMPLE_INPUT_LE_NATIVE_NI_STEREO = STEREO_NONINTERLEAVED,
- SAMPLE_INPUT_LE_NATIVE_MONO = STEREO_MONO,
- SAMPLE_INPUT_GT_NATIVE_I_STEREO = STEREO_INTERLEAVED + STEREO_NUM_MODES,
- SAMPLE_INPUT_GT_NATIVE_NI_STEREO = STEREO_NONINTERLEAVED + STEREO_NUM_MODES,
- SAMPLE_INPUT_GT_NATIVE_MONO = STEREO_MONO + STEREO_NUM_MODES,
- SAMPLE_INPUT_GT_NATIVE_1ST_INDEX = STEREO_NUM_MODES
-};
-
-enum
-{
- SAMPLE_OUTPUT_MONO = 0,
- SAMPLE_OUTPUT_STEREO,
- SAMPLE_OUTPUT_DITHERED_MONO,
- SAMPLE_OUTPUT_DITHERED_STEREO
-};
-
-/* No asm...yet */
-struct dither_data
-{
- long error[3]; /* 00h */
- long random; /* 0ch */
- /* 10h */
-};
-
-struct crossfeed_data
-{
- int32_t gain; /* 00h - Direct path gain */
- int32_t coefs[3]; /* 04h - Coefficients for the shelving filter */
- int32_t history[4]; /* 10h - Format is x[n - 1], y[n - 1] for both channels */
- int32_t delay[13][2]; /* 20h */
- int32_t *index; /* 88h - Current pointer into the delay line */
- /* 8ch */
-};
-
-/* Current setup is one lowshelf filters three peaking filters and one
- * highshelf filter. Varying the number of shelving filters make no sense,
- * but adding peaking filters is possible.
- */
-struct eq_state
-{
- char enabled[5]; /* 00h - Flags for active filters */
- struct eqfilter filters[5]; /* 08h - packing is 4? */
- /* 10ch */
-};
-
-/* Include header with defines which functions are implemented in assembly
- code for the target */
-#include <dsp_asm.h>
-
-/* Typedefs keep things much neater in this case */
-typedef void (*sample_input_fn_type)(int count, const char *src[],
- int32_t *dst[]);
-typedef int (*resample_fn_type)(int count, struct dsp_data *data,
- const int32_t *src[], int32_t *dst[]);
-typedef void (*sample_output_fn_type)(int count, struct dsp_data *data,
- const int32_t *src[], int16_t *dst);
-
-/* Single-DSP channel processing in place */
-typedef void (*channels_process_fn_type)(int count, int32_t *buf[]);
-/* DSP local channel processing in place */
-typedef void (*channels_process_dsp_fn_type)(int count, struct dsp_data *data,
- int32_t *buf[]);
-
-/*
- ***************************************************************************/
-
-struct dsp_config
-{
- struct dsp_data data; /* Config members for use in external routines */
- long codec_frequency; /* Sample rate of data coming from the codec */
- long frequency; /* Effective sample rate after pitch shift (if any) */
- int sample_depth;
- int sample_bytes;
- int stereo_mode;
- int32_t tdspeed_percent; /* Speed% * PITCH_SPEED_PRECISION */
-#ifdef HAVE_PITCHSCREEN
- bool tdspeed_active; /* Timestretch is in use */
-#endif
-#ifdef HAVE_SW_TONE_CONTROLS
- /* Filter struct for software bass/treble controls */
- struct eqfilter tone_filter;
-#endif
- /* Functions that change depending upon settings - NULL if stage is
- disabled */
- sample_input_fn_type input_samples;
- resample_fn_type resample;
- sample_output_fn_type output_samples;
- /* These will be NULL for the voice codec and is more economical that
- way */
- channels_process_dsp_fn_type apply_gain;
- channels_process_fn_type apply_crossfeed;
- channels_process_fn_type eq_process;
- channels_process_fn_type channels_process;
- channels_process_dsp_fn_type compressor_process;
-};
-
-/* General DSP config */
-static struct dsp_config dsp_conf[2] IBSS_ATTR; /* 0=A, 1=V */
-/* Dithering */
-static struct dither_data dither_data[2] IBSS_ATTR; /* 0=left, 1=right */
-static long dither_mask IBSS_ATTR;
-static long dither_bias IBSS_ATTR;
-/* Crossfeed */
-struct crossfeed_data crossfeed_data IDATA_ATTR = /* A */
-{
- .index = (int32_t *)crossfeed_data.delay
-};
-
-/* Equalizer */
-static struct eq_state eq_data; /* A */
-
-/* Software tone controls */
-#ifdef HAVE_SW_TONE_CONTROLS
-static int prescale; /* A/V */
-static int bass; /* A/V */
-static int treble; /* A/V */
-#endif
-
-/* Settings applicable to audio codec only */
-#ifdef HAVE_PITCHSCREEN
-static int32_t pitch_ratio = PITCH_SPEED_100;
-static int big_sample_locks;
-#endif
-static int channels_mode;
- long dsp_sw_gain;
- long dsp_sw_cross;
-static bool dither_enabled;
-static long eq_precut;
-static long track_gain;
-static bool new_gain;
-static long album_gain;
-static long track_peak;
-static long album_peak;
-static long replaygain;
-static bool crossfeed_enabled;
-
-#define AUDIO_DSP (dsp_conf[CODEC_IDX_AUDIO])
-#define VOICE_DSP (dsp_conf[CODEC_IDX_VOICE])
-
-/* The internal format is 32-bit samples, non-interleaved, stereo. This
- * format is similar to the raw output from several codecs, so the amount
- * of copying needed is minimized for that case.
- */
-
-#define RESAMPLE_RATIO 4 /* Enough for 11,025 Hz -> 44,100 Hz */
-#define SMALL_RESAMPLE_BUF_COUNT (SMALL_SAMPLE_BUF_COUNT * RESAMPLE_RATIO)
-#define BIG_SAMPLE_BUF_COUNT SMALL_RESAMPLE_BUF_COUNT
-#define BIG_RESAMPLE_BUF_COUNT (BIG_SAMPLE_BUF_COUNT * RESAMPLE_RATIO)
-
-static int32_t small_sample_buf[2][SMALL_SAMPLE_BUF_COUNT] IBSS_ATTR;
-static int32_t small_resample_buf[2][SMALL_RESAMPLE_BUF_COUNT] IBSS_ATTR;
-
-#ifdef HAVE_PITCHSCREEN
-static int32_t (* big_sample_buf)[BIG_SAMPLE_BUF_COUNT] = NULL;
-static int32_t (* big_resample_buf)[BIG_RESAMPLE_BUF_COUNT] = NULL;
-#endif
-
-static int sample_buf_count = SMALL_SAMPLE_BUF_COUNT;
-static int32_t *sample_buf[2] = { small_sample_buf[0], small_sample_buf[1] };
-static int resample_buf_count = SMALL_RESAMPLE_BUF_COUNT;
-static int32_t *resample_buf[2] = { small_resample_buf[0], small_resample_buf[1] };
-
-#ifdef HAVE_PITCHSCREEN
-int32_t sound_get_pitch(void)
-{
- return pitch_ratio;
-}
-
-void sound_set_pitch(int32_t percent)
-{
- pitch_ratio = percent;
- dsp_configure(&AUDIO_DSP, DSP_SWITCH_FREQUENCY,
- AUDIO_DSP.codec_frequency);
-}
-
-static void tdspeed_set_pointers( bool time_stretch_active )
-{
- if( time_stretch_active )
- {
- sample_buf_count = BIG_SAMPLE_BUF_COUNT;
- resample_buf_count = BIG_RESAMPLE_BUF_COUNT;
- sample_buf[0] = big_sample_buf[0];
- sample_buf[1] = big_sample_buf[1];
- resample_buf[0] = big_resample_buf[0];
- resample_buf[1] = big_resample_buf[1];
- }
- else
- {
- sample_buf_count = SMALL_SAMPLE_BUF_COUNT;
- resample_buf_count = SMALL_RESAMPLE_BUF_COUNT;
- sample_buf[0] = small_sample_buf[0];
- sample_buf[1] = small_sample_buf[1];
- resample_buf[0] = small_resample_buf[0];
- resample_buf[1] = small_resample_buf[1];
- }
-}
-
-static void tdspeed_setup(struct dsp_config *dspc)
-{
- /* Assume timestretch will not be used */
- dspc->tdspeed_active = false;
-
- tdspeed_set_pointers( false );
-
- if (!dsp_timestretch_available())
- return; /* Timestretch not enabled or buffer not allocated */
-
- if (dspc->tdspeed_percent == 0)
- dspc->tdspeed_percent = PITCH_SPEED_100;
-
- if (!tdspeed_config(
- dspc->codec_frequency == 0 ? NATIVE_FREQUENCY : dspc->codec_frequency,
- dspc->stereo_mode != STEREO_MONO,
- dspc->tdspeed_percent))
- return; /* Timestretch not possible or needed with these parameters */
-
- /* Timestretch is to be used */
- dspc->tdspeed_active = true;
-
- tdspeed_set_pointers( true );
-}
-
-
-static int move_callback(int handle, void* current, void* new)
-{
- (void)handle;(void)current;
-
- if ( big_sample_locks > 0 )
- return BUFLIB_CB_CANNOT_MOVE;
-
- big_sample_buf = new;
-
- /* no allocation without timestretch enabled */
- tdspeed_set_pointers( true );
- return BUFLIB_CB_OK;
-}
-
-static void lock_sample_buf( bool lock )
-{
- if ( lock )
- big_sample_locks++;
- else
- big_sample_locks--;
-}
-
-static struct buflib_callbacks ops = {
- .move_callback = move_callback,
- .shrink_callback = NULL,
-};
-
-
-void dsp_timestretch_enable(bool enabled)
-{
- /* Hook to set up timestretch buffer on first call to settings_apply() */
- static int handle = -1;
- if (enabled)
- {
- if (big_sample_buf)
- return; /* already allocated and enabled */
-
- /* Set up timestretch buffers */
- big_sample_buf = &small_resample_buf[0];
- handle = core_alloc_ex("resample buf",
- 2 * BIG_RESAMPLE_BUF_COUNT * sizeof(int32_t),
- &ops);
- big_sample_locks = 0;
- enabled = handle >= 0;
-
- if (enabled)
- {
- /* success, now setup tdspeed */
- big_resample_buf = core_get_data(handle);
-
- tdspeed_init();
- tdspeed_setup(&AUDIO_DSP);
- }
- }
-
- if (!enabled)
- {
- dsp_set_timestretch(PITCH_SPEED_100);
- tdspeed_finish();
-
- if (handle >= 0)
- core_free(handle);
-
- handle = -1;
- big_sample_buf = NULL;
- }
-}
-
-void dsp_set_timestretch(int32_t percent)
-{
- AUDIO_DSP.tdspeed_percent = percent;
- tdspeed_setup(&AUDIO_DSP);
-}
-
-int32_t dsp_get_timestretch()
-{
- return AUDIO_DSP.tdspeed_percent;
-}
-
-bool dsp_timestretch_available()
-{
- return (global_settings.timestretch_enabled && big_sample_buf);
-}
-#endif /* HAVE_PITCHSCREEN */
-
-/* Convert count samples to the internal format, if needed. Updates src
- * to point past the samples "consumed" and dst is set to point to the
- * samples to consume. Note that for mono, dst[0] equals dst[1], as there
- * is no point in processing the same data twice.
- */
-
-/* convert count 16-bit mono to 32-bit mono */
-static void sample_input_lte_native_mono(
- int count, const char *src[], int32_t *dst[])
-{
- const int16_t *s = (int16_t *) src[0];
- const int16_t * const send = s + count;
- int32_t *d = dst[0] = dst[1] = sample_buf[0];
- int scale = WORD_SHIFT;
-
- while (s < send)
- {
- *d++ = *s++ << scale;
- }
-
- src[0] = (char *)s;
-}
-
-/* convert count 16-bit interleaved stereo to 32-bit noninterleaved */
-static void sample_input_lte_native_i_stereo(
- int count, const char *src[], int32_t *dst[])
-{
- const int32_t *s = (int32_t *) src[0];
- const int32_t * const send = s + count;
- int32_t *dl = dst[0] = sample_buf[0];
- int32_t *dr = dst[1] = sample_buf[1];
- int scale = WORD_SHIFT;
-
- while (s < send)
- {
- int32_t slr = *s++;
-#ifdef ROCKBOX_LITTLE_ENDIAN
- *dl++ = (slr >> 16) << scale;
- *dr++ = (int32_t)(int16_t)slr << scale;
-#else /* ROCKBOX_BIG_ENDIAN */
- *dl++ = (int32_t)(int16_t)slr << scale;
- *dr++ = (slr >> 16) << scale;
-#endif
- }
-
- src[0] = (char *)s;
-}
-
-/* convert count 16-bit noninterleaved stereo to 32-bit noninterleaved */
-static void sample_input_lte_native_ni_stereo(
- int count, const char *src[], int32_t *dst[])
-{
- const int16_t *sl = (int16_t *) src[0];
- const int16_t *sr = (int16_t *) src[1];
- const int16_t * const slend = sl + count;
- int32_t *dl = dst[0] = sample_buf[0];
- int32_t *dr = dst[1] = sample_buf[1];
- int scale = WORD_SHIFT;
-
- while (sl < slend)
- {
- *dl++ = *sl++ << scale;
- *dr++ = *sr++ << scale;
- }
-
- src[0] = (char *)sl;
- src[1] = (char *)sr;
-}
-
-/* convert count 32-bit mono to 32-bit mono */
-static void sample_input_gt_native_mono(
- int count, const char *src[], int32_t *dst[])
-{
- dst[0] = dst[1] = (int32_t *)src[0];
- src[0] = (char *)(dst[0] + count);
-}
-
-/* convert count 32-bit interleaved stereo to 32-bit noninterleaved stereo */
-static void sample_input_gt_native_i_stereo(
- int count, const char *src[], int32_t *dst[])
-{
- const int32_t *s = (int32_t *)src[0];
- const int32_t * const send = s + 2*count;
- int32_t *dl = dst[0] = sample_buf[0];
- int32_t *dr = dst[1] = sample_buf[1];
-
- while (s < send)
- {
- *dl++ = *s++;
- *dr++ = *s++;
- }
-
- src[0] = (char *)send;
-}
-
-/* convert 32 bit-noninterleaved stereo to 32-bit noninterleaved stereo */
-static void sample_input_gt_native_ni_stereo(
- int count, const char *src[], int32_t *dst[])
-{
- dst[0] = (int32_t *)src[0];
- dst[1] = (int32_t *)src[1];
- src[0] = (char *)(dst[0] + count);
- src[1] = (char *)(dst[1] + count);
-}
-
-/**
- * sample_input_new_format()
- *
- * set the to-native sample conversion function based on dsp sample parameters
- *
- * !DSPPARAMSYNC
- * needs syncing with changes to the following dsp parameters:
- * * dsp->stereo_mode (A/V)
- * * dsp->sample_depth (A/V)
- */
-static void sample_input_new_format(struct dsp_config *dsp)
-{
- static const sample_input_fn_type sample_input_functions[] =
- {
- [SAMPLE_INPUT_LE_NATIVE_I_STEREO] = sample_input_lte_native_i_stereo,
- [SAMPLE_INPUT_LE_NATIVE_NI_STEREO] = sample_input_lte_native_ni_stereo,
- [SAMPLE_INPUT_LE_NATIVE_MONO] = sample_input_lte_native_mono,
- [SAMPLE_INPUT_GT_NATIVE_I_STEREO] = sample_input_gt_native_i_stereo,
- [SAMPLE_INPUT_GT_NATIVE_NI_STEREO] = sample_input_gt_native_ni_stereo,
- [SAMPLE_INPUT_GT_NATIVE_MONO] = sample_input_gt_native_mono,
- };
-
- int convert = dsp->stereo_mode;
-
- if (dsp->sample_depth > NATIVE_DEPTH)
- convert += SAMPLE_INPUT_GT_NATIVE_1ST_INDEX;
-
- dsp->input_samples = sample_input_functions[convert];
-}
-
-
-#ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO
-/* write mono internal format to output format */
-static void sample_output_mono(int count, struct dsp_data *data,
- const int32_t *src[], int16_t *dst)
-{
- const int32_t *s0 = src[0];
- const int scale = data->output_scale;
- const int dc_bias = 1 << (scale - 1);
-
- while (count-- > 0)
- {
- int32_t lr = clip_sample_16((*s0++ + dc_bias) >> scale);
- *dst++ = lr;
- *dst++ = lr;
- }
-}
-#endif /* DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO */
-
-/* write stereo internal format to output format */
-#ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO
-static void sample_output_stereo(int count, struct dsp_data *data,
- const int32_t *src[], int16_t *dst)
-{
- const int32_t *s0 = src[0];
- const int32_t *s1 = src[1];
- const int scale = data->output_scale;
- const int dc_bias = 1 << (scale - 1);
-
- while (count-- > 0)
- {
- *dst++ = clip_sample_16((*s0++ + dc_bias) >> scale);
- *dst++ = clip_sample_16((*s1++ + dc_bias) >> scale);
- }
-}
-#endif /* DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO */
-
-/**
- * The "dither" code to convert the 24-bit samples produced by libmad was
- * taken from the coolplayer project - coolplayer.sourceforge.net
- *
- * This function handles mono and stereo outputs.
- */
-static void sample_output_dithered(int count, struct dsp_data *data,
- const int32_t *src[], int16_t *dst)
-{
- const int32_t mask = dither_mask;
- const int32_t bias = dither_bias;
- const int scale = data->output_scale;
- const int32_t min = data->clip_min;
- const int32_t max = data->clip_max;
- const int32_t range = max - min;
- int ch;
- int16_t *d;
-
- for (ch = 0; ch < data->num_channels; ch++)
- {
- struct dither_data * const dither = &dither_data[ch];
- const int32_t *s = src[ch];
- int i;
-
- for (i = 0, d = &dst[ch]; i < count; i++, s++, d += 2)
- {
- int32_t output, sample;
- int32_t random;
-
- /* Noise shape and bias (for correct rounding later) */
- sample = *s;
- sample += dither->error[0] - dither->error[1] + dither->error[2];
- dither->error[2] = dither->error[1];
- dither->error[1] = dither->error[0]/2;
-
- output = sample + bias;
-
- /* Dither, highpass triangle PDF */
- random = dither->random*0x0019660dL + 0x3c6ef35fL;
- output += (random & mask) - (dither->random & mask);
- dither->random = random;
-
- /* Round sample to output range */
- output &= ~mask;
-
- /* Error feedback */
- dither->error[0] = sample - output;
-
- /* Clip */
- if ((uint32_t)(output - min) > (uint32_t)range)
- {
- int32_t c = min;
- if (output > min)
- c += range;
- output = c;
- }
-
- /* Quantize and store */
- *d = output >> scale;
- }
- }
-
- if (data->num_channels == 2)
- return;
-
- /* Have to duplicate left samples into the right channel since
- pcm buffer and hardware is interleaved stereo */
- d = &dst[0];
-
- while (count-- > 0)
- {
- int16_t s = *d++;
- *d++ = s;
- }
-}
-
-/**
- * sample_output_new_format()
- *
- * set the from-native to ouput sample conversion routine
- *
- * !DSPPARAMSYNC
- * needs syncing with changes to the following dsp parameters:
- * * dsp->stereo_mode (A/V)
- * * dither_enabled (A)
- */
-static void sample_output_new_format(struct dsp_config *dsp)
-{
- static const sample_output_fn_type sample_output_functions[] =
- {
- sample_output_mono,
- sample_output_stereo,
- sample_output_dithered,
- sample_output_dithered
- };
-
- int out = dsp->data.num_channels - 1;
-
- if (dsp == &AUDIO_DSP && dither_enabled)
- out += 2;
-
- dsp->output_samples = sample_output_functions[out];
-}
-
-/**
- * Linear interpolation resampling that introduces a one sample delay because
- * of our inability to look into the future at the end of a frame.
- */
-#ifndef DSP_HAVE_ASM_RESAMPLING
-static int dsp_downsample(int count, struct dsp_data *data,
- const int32_t *src[], int32_t *dst[])
-{
- int ch = data->num_channels - 1;
- uint32_t delta = data->resample_data.delta;
- uint32_t phase, pos;
- int32_t *d;
-
- /* Rolled channel loop actually showed slightly faster. */
- do
- {
- /* Just initialize things and not worry too much about the relatively
- * uncommon case of not being able to spit out a sample for the frame.
- */
- const int32_t *s = src[ch];
- int32_t last = data->resample_data.last_sample[ch];
-
- data->resample_data.last_sample[ch] = s[count - 1];
- d = dst[ch];
- phase = data->resample_data.phase;
- pos = phase >> 16;
-
- /* Do we need last sample of previous frame for interpolation? */
- if (pos > 0)
- last = s[pos - 1];
-
- while (pos < (uint32_t)count)
- {
- *d++ = last + FRACMUL((phase & 0xffff) << 15, s[pos] - last);
- phase += delta;
- pos = phase >> 16;
- last = s[pos - 1];
- }
- }
- while (--ch >= 0);
-
- /* Wrap phase accumulator back to start of next frame. */
- data->resample_data.phase = phase - (count << 16);
- return d - dst[0];
-}
-
-static int dsp_upsample(int count, struct dsp_data *data,
- const int32_t *src[], int32_t *dst[])
-{
- int ch = data->num_channels - 1;
- uint32_t delta = data->resample_data.delta;
- uint32_t phase, pos;
- int32_t *d;
-
- /* Rolled channel loop actually showed slightly faster. */
- do
- {
- /* Should always be able to output a sample for a ratio up to RESAMPLE_RATIO */
- const int32_t *s = src[ch];
- int32_t last = data->resample_data.last_sample[ch];
-
- data->resample_data.last_sample[ch] = s[count - 1];
- d = dst[ch];
- phase = data->resample_data.phase;
- pos = phase >> 16;
-
- while (pos == 0)
- {
- *d++ = last + FRACMUL((phase & 0xffff) << 15, s[0] - last);
- phase += delta;
- pos = phase >> 16;
- }
-
- while (pos < (uint32_t)count)
- {
- last = s[pos - 1];
- *d++ = last + FRACMUL((phase & 0xffff) << 15, s[pos] - last);
- phase += delta;
- pos = phase >> 16;
- }
- }
- while (--ch >= 0);
-
- /* Wrap phase accumulator back to start of next frame. */
- data->resample_data.phase = phase & 0xffff;
- return d - dst[0];
-}
-#endif /* DSP_HAVE_ASM_RESAMPLING */
-
-static void resampler_new_delta(struct dsp_config *dsp)
-{
- dsp->data.resample_data.delta = (unsigned long)
- dsp->frequency * 65536LL / NATIVE_FREQUENCY;
-
- if (dsp->frequency == NATIVE_FREQUENCY)
- {
- /* NOTE: If fully glitch-free transistions from no resampling to
- resampling are desired, last_sample history should be maintained
- even when not resampling. */
- dsp->resample = NULL;
- dsp->data.resample_data.phase = 0;
- dsp->data.resample_data.last_sample[0] = 0;
- dsp->data.resample_data.last_sample[1] = 0;
- }
- else if (dsp->frequency < NATIVE_FREQUENCY)
- dsp->resample = dsp_upsample;
- else
- dsp->resample = dsp_downsample;
-}
-
-/* Resample count stereo samples. Updates the src array, if resampling is
- * done, to refer to the resampled data. Returns number of stereo samples
- * for further processing.
- */
-static inline int resample(struct dsp_config *dsp, int count, int32_t *src[])
-{
- int32_t *dst[2] =
- {
- resample_buf[0],
- resample_buf[1]
- };
- lock_sample_buf( true );
- count = dsp->resample(count, &dsp->data, (const int32_t **)src, dst);
-
- src[0] = dst[0];
- src[1] = dst[dsp->data.num_channels - 1];
- lock_sample_buf( false );
- return count;
-}
-
-static void dither_init(struct dsp_config *dsp)
-{
- memset(dither_data, 0, sizeof (dither_data));
- dither_bias = (1L << (dsp->data.frac_bits - NATIVE_DEPTH));
- dither_mask = (1L << (dsp->data.frac_bits + 1 - NATIVE_DEPTH)) - 1;
-}
-
-void dsp_dither_enable(bool enable)
-{
- struct dsp_config *dsp = &AUDIO_DSP;
- dither_enabled = enable;
- sample_output_new_format(dsp);
-}
-
-/* Applies crossfeed to the stereo signal in src.
- * Crossfeed is a process where listening over speakers is simulated. This
- * is good for old hard panned stereo records, which might be quite fatiguing
- * to listen to on headphones with no crossfeed.
- */
-#ifndef DSP_HAVE_ASM_CROSSFEED
-static void apply_crossfeed(int count, int32_t *buf[])
-{
- int32_t *hist_l = &crossfeed_data.history[0];
- int32_t *hist_r = &crossfeed_data.history[2];
- int32_t *delay = &crossfeed_data.delay[0][0];
- int32_t *coefs = &crossfeed_data.coefs[0];
- int32_t gain = crossfeed_data.gain;
- int32_t *di = crossfeed_data.index;
-
- int32_t acc;
- int32_t left, right;
- int i;
-
- for (i = 0; i < count; i++)
- {
- left = buf[0][i];
- right = buf[1][i];
-
- /* Filter delayed sample from left speaker */
- acc = FRACMUL(*di, coefs[0]);
- acc += FRACMUL(hist_l[0], coefs[1]);
- acc += FRACMUL(hist_l[1], coefs[2]);
- /* Save filter history for left speaker */
- hist_l[1] = acc;
- hist_l[0] = *di;
- *di++ = left;
- /* Filter delayed sample from right speaker */
- acc = FRACMUL(*di, coefs[0]);
- acc += FRACMUL(hist_r[0], coefs[1]);
- acc += FRACMUL(hist_r[1], coefs[2]);
- /* Save filter history for right speaker */
- hist_r[1] = acc;
- hist_r[0] = *di;
- *di++ = right;
- /* Now add the attenuated direct sound and write to outputs */
- buf[0][i] = FRACMUL(left, gain) + hist_r[1];
- buf[1][i] = FRACMUL(right, gain) + hist_l[1];
-
- /* Wrap delay line index if bigger than delay line size */
- if (di >= delay + 13*2)
- di = delay;
- }
- /* Write back local copies of data we've modified */
- crossfeed_data.index = di;
-}
-#endif /* DSP_HAVE_ASM_CROSSFEED */
-
-/**
- * dsp_set_crossfeed(bool enable)
- *
- * !DSPPARAMSYNC
- * needs syncing with changes to the following dsp parameters:
- * * dsp->stereo_mode (A)
- */
-void dsp_set_crossfeed(bool enable)
-{
- crossfeed_enabled = enable;
- AUDIO_DSP.apply_crossfeed = (enable && AUDIO_DSP.data.num_channels > 1)
- ? apply_crossfeed : NULL;
-}
-
-void dsp_set_crossfeed_direct_gain(int gain)
-{
- crossfeed_data.gain = get_replaygain_int(gain * 10) << 7;
- /* If gain is negative, the calculation overflowed and we need to clamp */
- if (crossfeed_data.gain < 0)
- crossfeed_data.gain = 0x7fffffff;
-}
-
-/* Both gains should be below 0 dB */
-void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff)
-{
- int32_t *c = crossfeed_data.coefs;
- long scaler = get_replaygain_int(lf_gain * 10) << 7;
-
- cutoff = 0xffffffff/NATIVE_FREQUENCY*cutoff;
- hf_gain -= lf_gain;
- /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB
- * point instead of shelf midpoint. This is for compatibility with the old
- * crossfeed shelf filter and should be removed if crossfeed settings are
- * ever made incompatible for any other good reason.
- */
- cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24);
- filter_shelf_coefs(cutoff, hf_gain, false, c);
- /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains
- * over 1 and can do this safely
- */
- c[0] = FRACMUL_SHL(c[0], scaler, 4);
- c[1] = FRACMUL_SHL(c[1], scaler, 4);
- c[2] <<= 4;
-}
-
-/* Apply a constant gain to the samples (e.g., for ReplayGain).
- * Note that this must be called before the resampler.
- */
-#ifndef DSP_HAVE_ASM_APPLY_GAIN
-static void dsp_apply_gain(int count, struct dsp_data *data, int32_t *buf[])
-{
- const int32_t gain = data->gain;
- int ch;
-
- for (ch = 0; ch < data->num_channels; ch++)
- {
- int32_t *d = buf[ch];
- int i;
-
- for (i = 0; i < count; i++)
- d[i] = FRACMUL_SHL(d[i], gain, 8);
- }
-}
-#endif /* DSP_HAVE_ASM_APPLY_GAIN */
-
-/* Combine all gains to a global gain. */
-static void set_gain(struct dsp_config *dsp)
-{
- /* gains are in S7.24 format */
- dsp->data.gain = DEFAULT_GAIN;
-
- /* Replay gain not relevant to voice */
- if (dsp == &AUDIO_DSP && replaygain)
- {
- dsp->data.gain = replaygain;
- }
-
- if (dsp->eq_process && eq_precut)
- {
- dsp->data.gain = fp_mul(dsp->data.gain, eq_precut, 24);
- }
-
-#ifdef HAVE_SW_VOLUME_CONTROL
- if (global_settings.volume < SW_VOLUME_MAX ||
- global_settings.volume > SW_VOLUME_MIN)
- {
- int vol_gain = get_replaygain_int(global_settings.volume * 100);
- dsp->data.gain = (long) (((int64_t) dsp->data.gain * vol_gain) >> 24);
- }
-#endif
-
- if (dsp->data.gain == DEFAULT_GAIN)
- {
- dsp->data.gain = 0;
- }
- else
- {
- dsp->data.gain >>= 1; /* convert gain to S8.23 format */
- }
-
- dsp->apply_gain = dsp->data.gain != 0 ? dsp_apply_gain : NULL;
-}
-
-/**
- * Update the amount to cut the audio before applying the equalizer.
- *
- * @param precut to apply in decibels (multiplied by 10)
- */
-void dsp_set_eq_precut(int precut)
-{
- eq_precut = get_replaygain_int(precut * -10);
- set_gain(&AUDIO_DSP);
-}
-
-/**
- * Synchronize the equalizer filter coefficients with the global settings.
- *
- * @param band the equalizer band to synchronize
- */
-void dsp_set_eq_coefs(int band)
-{
- /* Adjust setting pointer to the band we actually want to change */
- struct eq_band_setting *setting = &global_settings.eq_band_settings[band];
-
- /* Convert user settings to format required by coef generator functions */
- unsigned long cutoff = 0xffffffff / NATIVE_FREQUENCY * setting->cutoff;
- unsigned long q = setting->q;
- int gain = setting->gain;
-
- if (q == 0)
- q = 1;
-
- /* NOTE: The coef functions assume the EMAC unit is in fractional mode,
- which it should be, since we're executed from the main thread. */
-
- /* Assume a band is disabled if the gain is zero */
- if (gain == 0)
- {
- eq_data.enabled[band] = 0;
- }
- else
- {
- if (band == 0)
- eq_ls_coefs(cutoff, q, gain, eq_data.filters[band].coefs);
- else if (band == 4)
- eq_hs_coefs(cutoff, q, gain, eq_data.filters[band].coefs);
- else
- eq_pk_coefs(cutoff, q, gain, eq_data.filters[band].coefs);
-
- eq_data.enabled[band] = 1;
- }
-}
-
-/* Apply EQ filters to those bands that have got it switched on. */
-static void eq_process(int count, int32_t *buf[])
-{
- static const int shifts[] =
- {
- EQ_SHELF_SHIFT, /* low shelf */
- EQ_PEAK_SHIFT, /* peaking */
- EQ_PEAK_SHIFT, /* peaking */
- EQ_PEAK_SHIFT, /* peaking */
- EQ_SHELF_SHIFT, /* high shelf */
- };
- unsigned int channels = AUDIO_DSP.data.num_channels;
- int i;
-
- /* filter configuration currently is 1 low shelf filter, 3 band peaking
- filters and 1 high shelf filter, in that order. we need to know this
- so we can choose the correct shift factor.
- */
- for (i = 0; i < 5; i++)
- {
- if (!eq_data.enabled[i])
- continue;
- eq_filter(buf, &eq_data.filters[i], count, channels, shifts[i]);
- }
-}
-
-/**
- * Use to enable the equalizer.
- *
- * @param enable true to enable the equalizer
- */
-void dsp_set_eq(bool enable)
-{
- AUDIO_DSP.eq_process = enable ? eq_process : NULL;
- set_gain(&AUDIO_DSP);
-}
-
-static void dsp_set_stereo_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 = ((int64_t)(0x7fffff + width) << 22) / width;
- cross = straight - 0x7fffff;
- }
-
- dsp_sw_gain = straight << 8;
- dsp_sw_cross = cross << 8;
-}
-
-/**
- * Implements the different channel configurations and stereo width.
- */
-
-/* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for
- * completeness. */
-#if 0
-static void channels_process_sound_chan_stereo(int count, int32_t *buf[])
-{
- /* The channels are each just themselves */
- (void)count; (void)buf;
-}
-#endif
-
-#ifndef DSP_HAVE_ASM_SOUND_CHAN_MONO
-static void channels_process_sound_chan_mono(int count, int32_t *buf[])
-{
- int32_t *sl = buf[0], *sr = buf[1];
-
- while (count-- > 0)
- {
- int32_t lr = *sl/2 + *sr/2;
- *sl++ = lr;
- *sr++ = lr;
- }
-}
-#endif /* DSP_HAVE_ASM_SOUND_CHAN_MONO */
-
-#ifndef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
-static void channels_process_sound_chan_custom(int count, int32_t *buf[])
-{
- const int32_t gain = dsp_sw_gain;
- const int32_t cross = dsp_sw_cross;
- int32_t *sl = buf[0], *sr = buf[1];
-
- while (count-- > 0)
- {
- int32_t l = *sl;
- int32_t r = *sr;
- *sl++ = FRACMUL(l, gain) + FRACMUL(r, cross);
- *sr++ = FRACMUL(r, gain) + FRACMUL(l, cross);
- }
-}
-#endif /* DSP_HAVE_ASM_SOUND_CHAN_CUSTOM */
-
-static void channels_process_sound_chan_mono_left(int count, int32_t *buf[])
-{
- /* Just copy over the other channel */
- memcpy(buf[1], buf[0], count * sizeof (*buf));
-}
-
-static void channels_process_sound_chan_mono_right(int count, int32_t *buf[])
-{
- /* Just copy over the other channel */
- memcpy(buf[0], buf[1], count * sizeof (*buf));
-}
-
-#ifndef DSP_HAVE_ASM_SOUND_CHAN_KARAOKE
-static void channels_process_sound_chan_karaoke(int count, int32_t *buf[])
-{
- int32_t *sl = buf[0], *sr = buf[1];
-
- while (count-- > 0)
- {
- int32_t ch = *sl/2 - *sr/2;
- *sl++ = ch;
- *sr++ = -ch;
- }
-}
-#endif /* DSP_HAVE_ASM_SOUND_CHAN_KARAOKE */
-
-static void dsp_set_channel_config(int value)
-{
- static const channels_process_fn_type channels_process_functions[] =
- {
- /* SOUND_CHAN_STEREO = All-purpose index for no channel processing */
- [SOUND_CHAN_STEREO] = NULL,
- [SOUND_CHAN_MONO] = channels_process_sound_chan_mono,
- [SOUND_CHAN_CUSTOM] = channels_process_sound_chan_custom,
- [SOUND_CHAN_MONO_LEFT] = channels_process_sound_chan_mono_left,
- [SOUND_CHAN_MONO_RIGHT] = channels_process_sound_chan_mono_right,
- [SOUND_CHAN_KARAOKE] = channels_process_sound_chan_karaoke,
- };
-
- if ((unsigned)value >= ARRAYLEN(channels_process_functions) ||
- AUDIO_DSP.stereo_mode == STEREO_MONO)
- {
- value = SOUND_CHAN_STEREO;
- }
-
- /* This doesn't apply to voice */
- channels_mode = value;
- AUDIO_DSP.channels_process = channels_process_functions[value];
-}
-
-#if CONFIG_CODEC == SWCODEC
-
-#ifdef HAVE_SW_TONE_CONTROLS
-static void set_tone_controls(void)
-{
- filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*200,
- 0xffffffff/NATIVE_FREQUENCY*3500,
- bass, treble, -prescale,
- AUDIO_DSP.tone_filter.coefs);
- /* Sync the voice dsp coefficients */
- memcpy(&VOICE_DSP.tone_filter.coefs, AUDIO_DSP.tone_filter.coefs,
- sizeof (VOICE_DSP.tone_filter.coefs));
-}
-#endif
-
-/* Hook back from firmware/ part of audio, which can't/shouldn't call apps/
- * code directly.
- */
-int dsp_callback(int msg, intptr_t param)
-{
- switch (msg)
- {
-#ifdef HAVE_SW_TONE_CONTROLS
- case DSP_CALLBACK_SET_PRESCALE:
- prescale = param;
- set_tone_controls();
- break;
- /* prescaler is always set after calling any of these, so we wait with
- * calculating coefs until the above case is hit.
- */
- case DSP_CALLBACK_SET_BASS:
- bass = param;
- break;
- case DSP_CALLBACK_SET_TREBLE:
- treble = param;
- break;
-#ifdef HAVE_SW_VOLUME_CONTROL
- case DSP_CALLBACK_SET_SW_VOLUME:
- set_gain(&AUDIO_DSP);
- break;
-#endif
-#endif
- case DSP_CALLBACK_SET_CHANNEL_CONFIG:
- dsp_set_channel_config(param);
- break;
- case DSP_CALLBACK_SET_STEREO_WIDTH:
- dsp_set_stereo_width(param);
- break;
- default:
- break;
- }
- return 0;
-}
-#endif
-
-/* Process and convert src audio to dst based on the DSP configuration,
- * reading count number of audio samples. dst is assumed to be large
- * enough; use dsp_output_count() to get the required number. src is an
- * array of pointers; for mono and interleaved stereo, it contains one
- * pointer to the start of the audio data and the other is ignored; for
- * non-interleaved stereo, it contains two pointers, one for each audio
- * channel. Returns number of bytes written to dst.
- */
-int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count)
-{
- static int32_t *tmp[2]; /* tdspeed_doit() needs it static */
- static long last_yield;
- long tick;
- int written = 0;
-
-#if defined(CPU_COLDFIRE)
- /* set emac unit for dsp processing, and save old macsr, we're running in
- codec thread context at this point, so can't clobber it */
- unsigned long old_macsr = coldfire_get_macsr();
- coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
-#endif
-
- if (new_gain)
- dsp_set_replaygain(); /* Gain has changed */
-
- /* Perform at least one yield before starting */
- last_yield = current_tick;
- yield();
-
- /* Testing function pointers for NULL is preferred since the pointer
- will be preloaded to be used for the call if not. */
- while (count > 0)
- {
- int samples = MIN(sample_buf_count, count);
- count -= samples;
-
- dsp->input_samples(samples, src, tmp);
-
-#ifdef HAVE_PITCHSCREEN
- if (dsp->tdspeed_active)
- samples = tdspeed_doit(tmp, samples);
-#endif
-
- int chunk_offset = 0;
- while (samples > 0)
- {
- int32_t *t2[2];
- t2[0] = tmp[0]+chunk_offset;
- t2[1] = tmp[1]+chunk_offset;
-
- int chunk = MIN(sample_buf_count, samples);
- chunk_offset += chunk;
- samples -= chunk;
-
- if (dsp->apply_gain)
- dsp->apply_gain(chunk, &dsp->data, t2);
-
- if (dsp->resample && (chunk = resample(dsp, chunk, t2)) <= 0)
- break; /* I'm pretty sure we're downsampling here */
-
- if (dsp->apply_crossfeed)
- dsp->apply_crossfeed(chunk, t2);
-
- if (dsp->eq_process)
- dsp->eq_process(chunk, t2);
-
-#ifdef HAVE_SW_TONE_CONTROLS
- if ((bass | treble) != 0)
- eq_filter(t2, &dsp->tone_filter, chunk,
- dsp->data.num_channels, FILTER_BISHELF_SHIFT);
-#endif
-
- if (dsp->channels_process)
- dsp->channels_process(chunk, t2);
-
- if (dsp->compressor_process)
- dsp->compressor_process(chunk, &dsp->data, t2);
-
- dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst);
-
- written += chunk;
- dst += chunk * sizeof (int16_t) * 2;
-
- /* yield at least once each tick */
- tick = current_tick;
- if (TIME_AFTER(tick, last_yield))
- {
- last_yield = tick;
- yield();
- }
- }
- }
-
-#if defined(CPU_COLDFIRE)
- /* set old macsr again */
- coldfire_set_macsr(old_macsr);
-#endif
- return written;
-}
-
-/* Given count number of input samples, calculate the maximum number of
- * samples of output data that would be generated (the calculation is not
- * entirely exact and rounds upwards to be on the safe side; during
- * resampling, the number of samples generated depends on the current state
- * of the resampler).
- */
-/* dsp_input_size MUST be called afterwards */
-int dsp_output_count(struct dsp_config *dsp, int count)
-{
-#ifdef HAVE_PITCHSCREEN
- if (dsp->tdspeed_active)
- count = tdspeed_est_output_size();
-#endif
- if (dsp->resample)
- {
- count = (int)(((unsigned long)count * NATIVE_FREQUENCY
- + (dsp->frequency - 1)) / dsp->frequency);
- }
-
- /* Now we have the resampled sample count which must not exceed
- * resample_buf_count to avoid resample buffer overflow. One
- * must call dsp_input_count() to get the correct input sample
- * count.
- */
- if (count > resample_buf_count)
- count = resample_buf_count;
-
- return count;
-}
-
-/* Given count output samples, calculate number of input samples
- * that would be consumed in order to fill the output buffer.
- */
-int dsp_input_count(struct dsp_config *dsp, int count)
-{
- /* count is now the number of resampled input samples. Convert to
- original input samples. */
- if (dsp->resample)
- {
- /* Use the real resampling delta =
- * dsp->frequency * 65536 / NATIVE_FREQUENCY, and
- * round towards zero to avoid buffer overflows. */
- count = (int)(((unsigned long)count *
- dsp->data.resample_data.delta) >> 16);
- }
-
-#ifdef HAVE_PITCHSCREEN
- if (dsp->tdspeed_active)
- count = tdspeed_est_input_size(count);
-#endif
-
- return count;
-}
-
-static void dsp_set_gain_var(long *var, long value)
-{
- *var = value;
- new_gain = true;
-}
-
-static void dsp_update_functions(struct dsp_config *dsp)
-{
- sample_input_new_format(dsp);
- sample_output_new_format(dsp);
- if (dsp == &AUDIO_DSP)
- dsp_set_crossfeed(crossfeed_enabled);
-}
-
-intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value)
-{
- switch (setting)
- {
- case DSP_MYDSP:
- switch (value)
- {
- case CODEC_IDX_AUDIO:
- return (intptr_t)&AUDIO_DSP;
- case CODEC_IDX_VOICE:
- return (intptr_t)&VOICE_DSP;
- default:
- return (intptr_t)NULL;
- }
-
- case DSP_SET_FREQUENCY:
- memset(&dsp->data.resample_data, 0, sizeof (dsp->data.resample_data));
- /* Fall through!!! */
- case DSP_SWITCH_FREQUENCY:
- dsp->codec_frequency = (value == 0) ? NATIVE_FREQUENCY : value;
- /* Account for playback speed adjustment when setting dsp->frequency
- if we're called from the main audio thread. Voice UI thread should
- not need this feature.
- */
-#ifdef HAVE_PITCHSCREEN
- if (dsp == &AUDIO_DSP)
- dsp->frequency = pitch_ratio * dsp->codec_frequency / PITCH_SPEED_100;
- else
-#endif
- dsp->frequency = dsp->codec_frequency;
-
- resampler_new_delta(dsp);
-#ifdef HAVE_PITCHSCREEN
- tdspeed_setup(dsp);
-#endif
- break;
-
- case DSP_SET_SAMPLE_DEPTH:
- dsp->sample_depth = value;
-
- if (dsp->sample_depth <= NATIVE_DEPTH)
- {
- dsp->data.frac_bits = WORD_FRACBITS;
- dsp->sample_bytes = sizeof (int16_t); /* samples are 16 bits */
- dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1);
- dsp->data.clip_min = -((1 << WORD_FRACBITS));
- }
- else
- {
- dsp->data.frac_bits = value;
- dsp->sample_bytes = sizeof (int32_t); /* samples are 32 bits */
- dsp->data.clip_max = (1 << value) - 1;
- dsp->data.clip_min = -(1 << value);
- }
-
- dsp->data.output_scale = dsp->data.frac_bits + 1 - NATIVE_DEPTH;
- sample_input_new_format(dsp);
- dither_init(dsp);
- break;
-
- case DSP_SET_STEREO_MODE:
- dsp->stereo_mode = value;
- dsp->data.num_channels = value == STEREO_MONO ? 1 : 2;
- dsp_update_functions(dsp);
-#ifdef HAVE_PITCHSCREEN
- tdspeed_setup(dsp);
-#endif
- break;
-
- case DSP_RESET:
- dsp->stereo_mode = STEREO_NONINTERLEAVED;
- dsp->data.num_channels = 2;
- dsp->sample_depth = NATIVE_DEPTH;
- dsp->data.frac_bits = WORD_FRACBITS;
- dsp->sample_bytes = sizeof (int16_t);
- dsp->data.output_scale = dsp->data.frac_bits + 1 - NATIVE_DEPTH;
- dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1);
- dsp->data.clip_min = -((1 << WORD_FRACBITS));
- dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY;
-
- if (dsp == &AUDIO_DSP)
- {
- track_gain = 0;
- album_gain = 0;
- track_peak = 0;
- album_peak = 0;
- new_gain = true;
- }
-
- dsp_update_functions(dsp);
- resampler_new_delta(dsp);
-#ifdef HAVE_PITCHSCREEN
- tdspeed_setup(dsp);
-#endif
- if (dsp == &AUDIO_DSP)
- compressor_reset();
- break;
-
- case DSP_FLUSH:
- memset(&dsp->data.resample_data, 0,
- sizeof (dsp->data.resample_data));
- resampler_new_delta(dsp);
- dither_init(dsp);
-#ifdef HAVE_PITCHSCREEN
- tdspeed_setup(dsp);
-#endif
- if (dsp == &AUDIO_DSP)
- compressor_reset();
- break;
-
- case DSP_SET_TRACK_GAIN:
- if (dsp == &AUDIO_DSP)
- dsp_set_gain_var(&track_gain, value);
- break;
-
- case DSP_SET_ALBUM_GAIN:
- if (dsp == &AUDIO_DSP)
- dsp_set_gain_var(&album_gain, value);
- break;
-
- case DSP_SET_TRACK_PEAK:
- if (dsp == &AUDIO_DSP)
- dsp_set_gain_var(&track_peak, value);
- break;
-
- case DSP_SET_ALBUM_PEAK:
- if (dsp == &AUDIO_DSP)
- dsp_set_gain_var(&album_peak, value);
- break;
-
- default:
- return 0;
- }
-
- return 1;
-}
-
-int get_replaygain_mode(bool have_track_gain, bool have_album_gain)
-{
- int type;
-
- bool track = ((global_settings.replaygain_type == REPLAYGAIN_TRACK)
- || ((global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
- && global_settings.playlist_shuffle));
-
- type = (!track && have_album_gain) ? REPLAYGAIN_ALBUM
- : have_track_gain ? REPLAYGAIN_TRACK : -1;
-
- return type;
-}
-
-void dsp_set_replaygain(void)
-{
- long gain = 0;
-
- new_gain = false;
-
- if ((global_settings.replaygain_type != REPLAYGAIN_OFF) ||
- global_settings.replaygain_noclip)
- {
- bool track_mode = get_replaygain_mode(track_gain != 0,
- album_gain != 0) == REPLAYGAIN_TRACK;
- long peak = (track_mode || !album_peak) ? track_peak : album_peak;
-
- if (global_settings.replaygain_type != REPLAYGAIN_OFF)
- {
- gain = (track_mode || !album_gain) ? track_gain : album_gain;
-
- if (global_settings.replaygain_preamp)
- {
- long preamp = get_replaygain_int(
- global_settings.replaygain_preamp * 10);
-
- gain = (long) (((int64_t) gain * preamp) >> 24);
- }
- }
-
- if (gain == 0)
- {
- /* So that noclip can work even with no gain information. */
- gain = DEFAULT_GAIN;
- }
-
- if (global_settings.replaygain_noclip && (peak != 0)
- && ((((int64_t) gain * peak) >> 24) >= DEFAULT_GAIN))
- {
- gain = (((int64_t) DEFAULT_GAIN << 24) / peak);
- }
-
- if (gain == DEFAULT_GAIN)
- {
- /* Nothing to do, disable processing. */
- gain = 0;
- }
- }
-
- /* Store in S7.24 format to simplify calculations. */
- replaygain = gain;
- set_gain(&AUDIO_DSP);
-}
-
-/** SET COMPRESSOR
- * Called by the menu system to configure the compressor process */
-void dsp_set_compressor(void)
-{
- /* enable/disable the compressor */
- AUDIO_DSP.compressor_process = compressor_update() ?
- compressor_process : NULL;
-}