summaryrefslogtreecommitdiff
path: root/lib/rbcodec/dsp/pga.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/dsp/pga.c')
-rw-r--r--lib/rbcodec/dsp/pga.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/lib/rbcodec/dsp/pga.c b/lib/rbcodec/dsp/pga.c
new file mode 100644
index 0000000000..c2c29ccfc0
--- /dev/null
+++ b/lib/rbcodec/dsp/pga.c
@@ -0,0 +1,144 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Magnus Holmgren
11 * Copyright (C) 2012 Michael Sevakis
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include "config.h"
23#include "system.h"
24#include "dsp.h"
25#include "dsp-util.h"
26#include "fixedpoint.h"
27#include "fracmul.h"
28#include "dsp_proc_entry.h"
29
30/* Implemented here or in target assembly code */
31void pga_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p);
32
33#define DEFAULT_PGA_GAIN (PGA_UNITY >> 1) /* s8.23 format */
34
35static struct pga_data
36{
37 int32_t gain; /* 00h: Final gain in s8.23 format */
38 uint32_t enabled; /* Mask of enabled gains */
39 int32_t gains[PGA_NUM_GAINS]; /* Individual gains in s7.24 format */
40} pga_data =
41{
42 .gain = DEFAULT_PGA_GAIN,
43 .enabled = 0,
44 .gains[0 ... PGA_NUM_GAINS-1] = PGA_UNITY,
45};
46
47/* Combine all gains to a global gain and enable/disable the amplifier if
48 the overall gain is not unity/unity */
49static void pga_update(void)
50{
51 int32_t gain = PGA_UNITY;
52
53 /* Multiply all gains with one another to get overall amp gain */
54 for (int i = 0; i < PGA_NUM_GAINS; i++)
55 {
56 if (pga_data.enabled & BIT_N(i)) /* Only enabled gains factor in */
57 gain = fp_mul(gain, pga_data.gains[i], 24);
58 }
59
60 gain >>= 1; /* s7.24 -> s8.23 format */
61
62 if (gain == pga_data.gain)
63 return;
64
65 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
66 pga_data.gain = gain;
67 dsp_proc_enable(dsp, DSP_PROC_PGA, gain != DEFAULT_PGA_GAIN);
68 dsp_proc_activate(dsp, DSP_PROC_PGA, true);
69}
70
71
72/** Amp controls **/
73
74/* Set a particular gain value - doesn't have to be enabled */
75void pga_set_gain(enum pga_gain_ids id, int32_t value)
76{
77 if (value == pga_data.gains[id])
78 return;
79
80 pga_data.gains[id] = value;
81
82 if (BIT_N(id) & pga_data.enabled)
83 pga_update();
84}
85
86/* Enable or disable the specified gain stage */
87void pga_enable_gain(enum pga_gain_ids id, bool enable)
88{
89 uint32_t bit = BIT_N(id);
90
91 if (enable != !(pga_data.enabled & bit))
92 return;
93
94 pga_data.enabled ^= bit;
95 pga_update();
96}
97
98
99/** DSP interface **/
100
101#if !defined(CPU_COLDFIRE) && !defined(CPU_ARM)
102/* Apply a constant gain to the samples (e.g., for ReplayGain). */
103void pga_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p)
104{
105 int32_t gain = ((struct pga_data *)this->data)->gain;
106 struct dsp_buffer *buf = *buf_p;
107 unsigned int channels = buf->format.num_channels;
108
109 for (unsigned int ch = 0; ch < channels; ch++)
110 {
111 int32_t *d = buf->p32[ch];
112 int count = buf->remcount;
113
114 for (int i = 0; i < count; i++)
115 d[i] = FRACMUL_SHL(d[i], gain, 8);
116 }
117
118 (void)this;
119}
120#endif /* CPU */
121
122/* DSP message hook */
123static intptr_t pga_configure(struct dsp_proc_entry *this,
124 struct dsp_config *dsp,
125 unsigned int setting,
126 intptr_t value)
127{
128 switch (setting)
129 {
130 case DSP_PROC_INIT:
131 if (value != 0)
132 break; /* Already initialized */
133 this->data = (intptr_t)&pga_data;
134 this->process[0] = pga_process;
135 break;
136 }
137
138 return 1;
139 (void)dsp;
140}
141
142/* Database entry */
143DSP_PROC_DB_ENTRY(PGA,
144 pga_configure);