summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2012-12-19 17:34:57 -0500
committerMichael Sevakis <jethead71@rockbox.org>2013-05-04 13:43:33 -0400
commit78a45b47dede5ddf35dfc53e965b486a79177b18 (patch)
treeedb3ad7c101e600a7cc3be4b40380430cbeb3e55
parentcdb71c707bb434f44368b72f2db3becc37b7a46c (diff)
downloadrockbox-78a45b47dede5ddf35dfc53e965b486a79177b18.tar.gz
rockbox-78a45b47dede5ddf35dfc53e965b486a79177b18.zip
Cleanup and simplify latest DSP code incarnation.
Some things can just be a bit simpler in handling the list of stages and some things, especially format change handling, can be simplified for each stage implementation. Format changes are sent through the configure() callback. Hide some internal details and variables from processing stages and let the core deal with it. Do some miscellaneous cleanup and keep things a bit better factored. Change-Id: I19dd8ce1d0b792ba914d426013088a49a52ecb7e
-rw-r--r--lib/rbcodec/dsp/channel_mode.c98
-rw-r--r--lib/rbcodec/dsp/compressor.c6
-rw-r--r--lib/rbcodec/dsp/crossfeed.c122
-rw-r--r--lib/rbcodec/dsp/dsp_core.c342
-rw-r--r--lib/rbcodec/dsp/dsp_core.h37
-rw-r--r--lib/rbcodec/dsp/dsp_misc.c35
-rw-r--r--lib/rbcodec/dsp/dsp_proc_entry.h43
-rw-r--r--lib/rbcodec/dsp/dsp_sample_input.c92
-rw-r--r--lib/rbcodec/dsp/dsp_sample_io.h23
-rw-r--r--lib/rbcodec/dsp/dsp_sample_output.c33
-rw-r--r--lib/rbcodec/dsp/eq.c8
-rw-r--r--lib/rbcodec/dsp/lin_resample.c97
-rw-r--r--lib/rbcodec/dsp/pga.c7
-rw-r--r--lib/rbcodec/dsp/tdspeed.c100
-rw-r--r--lib/rbcodec/dsp/tone_controls.c10
15 files changed, 513 insertions, 540 deletions
diff --git a/lib/rbcodec/dsp/channel_mode.c b/lib/rbcodec/dsp/channel_mode.c
index 78e7b8f10c..2ae2d45fd3 100644
--- a/lib/rbcodec/dsp/channel_mode.c
+++ b/lib/rbcodec/dsp/channel_mode.c
@@ -49,30 +49,14 @@ static struct channel_mode_data
49{ 49{
50 long sw_gain; /* 00h: for mode: custom */ 50 long sw_gain; /* 00h: for mode: custom */
51 long sw_cross; /* 04h: for mode: custom */ 51 long sw_cross; /* 04h: for mode: custom */
52 struct dsp_config *dsp;
53 int mode; 52 int mode;
54 const dsp_proc_fn_type fns[SOUND_CHAN_NUM_MODES];
55} channel_mode_data = 53} channel_mode_data =
56{ 54{
57 .sw_gain = 0, 55 .sw_gain = 0,
58 .sw_cross = 0, 56 .sw_cross = 0,
59 .mode = SOUND_CHAN_STEREO, 57 .mode = SOUND_CHAN_STEREO
60 .fns =
61 {
62 [SOUND_CHAN_STEREO] = NULL,
63 [SOUND_CHAN_MONO] = channel_mode_proc_mono,
64 [SOUND_CHAN_CUSTOM] = channel_mode_proc_custom,
65 [SOUND_CHAN_MONO_LEFT] = channel_mode_proc_mono_left,
66 [SOUND_CHAN_MONO_RIGHT] = channel_mode_proc_mono_right,
67 [SOUND_CHAN_KARAOKE] = channel_mode_proc_karaoke,
68 },
69}; 58};
70 59
71static dsp_proc_fn_type get_process_fn(void)
72{
73 return channel_mode_data.fns[channel_mode_data.mode];
74}
75
76#if 0 60#if 0
77/* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for 61/* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for
78 * completeness. */ 62 * completeness. */
@@ -166,33 +150,6 @@ void channel_mode_proc_mono_right(struct dsp_proc_entry *this,
166 (void)this; 150 (void)this;
167} 151}
168 152
169/* This is the initial function pointer when first enabled/changed in order
170 * to facilitate verification of the format compatibility at the proper time
171 * This gets called for changes even if stage is inactive. */
172static void channel_mode_process_new_format(struct dsp_proc_entry *this,
173 struct dsp_buffer **buf_p)
174{
175 struct channel_mode_data *data = (void *)this->data;
176 struct dsp_buffer *buf = *buf_p;
177
178 DSP_PRINT_FORMAT(DSP_PROC_CHANNEL_MODE, DSP_PROC_CHANNEL_MODE,
179 buf->format);
180
181 bool active = buf->format.num_channels >= 2;
182 dsp_proc_activate(data->dsp, DSP_PROC_CHANNEL_MODE, active);
183
184 if (!active)
185 {
186 /* Can't do this. Sleep until next change. */
187 DEBUGF(" DSP_PROC_CHANNEL_MODE- deactivated\n");
188 return;
189 }
190
191 /* Switch to the real function and call it once */
192 this->process[0] = get_process_fn();
193 dsp_proc_call(this, buf_p, (unsigned)buf->format.changed - 1);
194}
195
196void channel_mode_set_config(int value) 153void channel_mode_set_config(int value)
197{ 154{
198 if (value < 0 || value >= SOUND_CHAN_NUM_MODES) 155 if (value < 0 || value >= SOUND_CHAN_NUM_MODES)
@@ -228,34 +185,65 @@ void channel_mode_custom_set_width(int value)
228 channel_mode_data.sw_cross = cross << 8; 185 channel_mode_data.sw_cross = cross << 8;
229} 186}
230 187
188static void update_process_fn(struct dsp_proc_entry *this)
189{
190 static const dsp_proc_fn_type fns[SOUND_CHAN_NUM_MODES] =
191 {
192 [SOUND_CHAN_STEREO] = NULL,
193 [SOUND_CHAN_MONO] = channel_mode_proc_mono,
194 [SOUND_CHAN_CUSTOM] = channel_mode_proc_custom,
195 [SOUND_CHAN_MONO_LEFT] = channel_mode_proc_mono_left,
196 [SOUND_CHAN_MONO_RIGHT] = channel_mode_proc_mono_right,
197 [SOUND_CHAN_KARAOKE] = channel_mode_proc_karaoke,
198 };
199
200 this->process = fns[((struct channel_mode_data *)this->data)->mode];
201}
202
203/* Handle format changes and verify the format compatibility */
204static intptr_t channel_mode_new_format(struct dsp_proc_entry *this,
205 struct dsp_config *dsp,
206 struct sample_format *format)
207{
208 DSP_PRINT_FORMAT(DSP_PROC_CHANNEL_MODE, format);
209
210 bool active = format->num_channels >= 2;
211 dsp_proc_activate(dsp, DSP_PROC_CHANNEL_MODE, active);
212
213 if (active)
214 return PROC_NEW_FORMAT_OK;
215
216 /* Can't do this. Sleep until next change. */
217 DEBUGF(" DSP_PROC_CHANNEL_MODE- deactivated\n");
218 return PROC_NEW_FORMAT_DEACTIVATED;
219
220 (void)this;
221}
222
231/* DSP message hook */ 223/* DSP message hook */
232static intptr_t channel_mode_configure(struct dsp_proc_entry *this, 224static intptr_t channel_mode_configure(struct dsp_proc_entry *this,
233 struct dsp_config *dsp, 225 struct dsp_config *dsp,
234 unsigned int setting, 226 unsigned int setting,
235 intptr_t value) 227 intptr_t value)
236{ 228{
229 intptr_t retval = 0;
230
237 switch (setting) 231 switch (setting)
238 { 232 {
239 case DSP_PROC_INIT: 233 case DSP_PROC_INIT:
240 if (value == 0) 234 if (value == 0)
241 {
242 /* New object */
243 this->data = (intptr_t)&channel_mode_data; 235 this->data = (intptr_t)&channel_mode_data;
244 this->process[1] = channel_mode_process_new_format;
245 ((struct channel_mode_data *)this->data)->dsp = dsp;
246 }
247 236
248 /* Force format change call each time */ 237 update_process_fn(this);
249 this->process[0] = channel_mode_process_new_format;
250 dsp_proc_activate(dsp, DSP_PROC_CHANNEL_MODE, true);
251 break; 238 break;
252 239
253 case DSP_PROC_CLOSE: 240 case DSP_PROC_NEW_FORMAT:
254 ((struct channel_mode_data *)this->data)->dsp = NULL; 241 retval = channel_mode_new_format(this, dsp,
242 (struct sample_format *)value);
255 break; 243 break;
256 } 244 }
257 245
258 return 1; 246 return retval;
259} 247}
260 248
261/* Database entry */ 249/* Database entry */
diff --git a/lib/rbcodec/dsp/compressor.c b/lib/rbcodec/dsp/compressor.c
index 22a60e4c7e..bdcc37be91 100644
--- a/lib/rbcodec/dsp/compressor.c
+++ b/lib/rbcodec/dsp/compressor.c
@@ -386,14 +386,16 @@ static intptr_t compressor_configure(struct dsp_proc_entry *this,
386 case DSP_PROC_INIT: 386 case DSP_PROC_INIT:
387 if (value != 0) 387 if (value != 0)
388 break; /* Already enabled */ 388 break; /* Already enabled */
389 this->process[0] = compressor_process; 389
390 this->process = compressor_process;
391 /* Fall-through */
390 case DSP_RESET: 392 case DSP_RESET:
391 case DSP_FLUSH: 393 case DSP_FLUSH:
392 release_gain = UNITY; 394 release_gain = UNITY;
393 break; 395 break;
394 } 396 }
395 397
396 return 1; 398 return 0;
397 (void)dsp; 399 (void)dsp;
398} 400}
399 401
diff --git a/lib/rbcodec/dsp/crossfeed.c b/lib/rbcodec/dsp/crossfeed.c
index 3fb51a7594..bd8ee95042 100644
--- a/lib/rbcodec/dsp/crossfeed.c
+++ b/lib/rbcodec/dsp/crossfeed.c
@@ -68,8 +68,7 @@ static struct crossfeed_state
68 }; 68 };
69 }; 69 };
70 int32_t *index; /* 88h: Current pointer into the delay line */ 70 int32_t *index; /* 88h: Current pointer into the delay line */
71 struct dsp_config *dsp; /* 8ch: Current DSP */ 71 /* 8ch */
72 /* 90h */
73} crossfeed_state IBSS_ATTR; 72} crossfeed_state IBSS_ATTR;
74 73
75static int crossfeed_type = CROSSFEED_TYPE_NONE; 74static int crossfeed_type = CROSSFEED_TYPE_NONE;
@@ -79,62 +78,21 @@ static void crossfeed_flush(struct dsp_proc_entry *this)
79{ 78{
80 struct crossfeed_state *state = (void *)this->data; 79 struct crossfeed_state *state = (void *)this->data;
81 80
82 if (crossfeed_type == CROSSFEED_TYPE_CUSTOM) 81 if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
83 { 82 {
84 memset(state->history, 0, 83 state->vcl = state->vcr = state->vdiff = 0;
85 sizeof (state->history) + sizeof (state->delay));
86 state->index = state->delay;
87 } 84 }
88 else 85 else
89 { 86 {
90 state->vcl = state->vcr = state->vdiff = 0; 87 memset(state->history, 0,
88 sizeof (state->history) + sizeof (state->delay));
89 state->index = state->delay;
91 } 90 }
92} 91}
93 92
94 93
95/** DSP interface **/ 94/** DSP interface **/
96 95
97/* Crossfeed boot/format change function */
98static void crossfeed_process_new_format(struct dsp_proc_entry *this,
99 struct dsp_buffer **buf_p)
100{
101 struct crossfeed_state *state = (void *)this->data;
102 struct dsp_buffer *buf = *buf_p;
103
104 DSP_PRINT_FORMAT(DSP_PROC_CROSSFEED, DSP_PROC_CROSSFEED, buf->format);
105
106 bool was_active = dsp_proc_active(state->dsp, DSP_PROC_CROSSFEED);
107 bool active = buf->format.num_channels >= 2;
108 dsp_proc_activate(state->dsp, DSP_PROC_CROSSFEED, active);
109
110 if (!active)
111 {
112 /* Can't do this. Sleep until next change */
113 DEBUGF(" DSP_PROC_CROSSFEED- deactivated\n");
114 return;
115 }
116
117 dsp_proc_fn_type fn = crossfeed_process;
118
119 if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
120 {
121 /* 1 / (F.Rforward.C) */
122 state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128;
123 /* 1 / (F.Rcross.C) */
124 state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000;
125 fn = crossfeed_meier_process;
126 }
127
128 if (!was_active || this->process[0] != fn)
129 {
130 crossfeed_flush(this); /* Going online or actual type change */
131 this->process[0] = fn; /* Set real function */
132 }
133
134 /* Call it once */
135 dsp_proc_call(this, buf_p, (unsigned)buf->format.changed - 1);
136}
137
138/* Set the type of crossfeed to use */ 96/* Set the type of crossfeed to use */
139void dsp_set_crossfeed_type(int type) 97void dsp_set_crossfeed_type(int type)
140{ 98{
@@ -273,39 +231,83 @@ void crossfeed_meier_process(struct dsp_proc_entry *this,
273} 231}
274#endif /* CPU */ 232#endif /* CPU */
275 233
234/* Update the processing function according to crossfeed type */
235static void update_process_fn(struct dsp_proc_entry *this,
236 struct dsp_config *dsp)
237{
238 struct crossfeed_state *state = (struct crossfeed_state *)this->data;
239 dsp_proc_fn_type fn = crossfeed_process;
240
241 if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
242 {
243 /* Set up for Meier */
244 /* 1 / (F.Rforward.C) */
245 state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128;
246 /* 1 / (F.Rcross.C) */
247 state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000;
248 fn = crossfeed_meier_process;
249 }
250
251 if (this->process != fn)
252 {
253 this->process = fn; /* Set proper function */
254 if (dsp_proc_active(dsp, DSP_PROC_CROSSFEED))
255 crossfeed_flush(this);
256 }
257}
258
259/* Crossfeed boot/format change function */
260static intptr_t crossfeed_new_format(struct dsp_proc_entry *this,
261 struct dsp_config *dsp,
262 struct sample_format *format)
263{
264 DSP_PRINT_FORMAT(DSP_PROC_CROSSFEED, format);
265
266 bool was_active = dsp_proc_active(dsp, DSP_PROC_CROSSFEED);
267 bool active = format->num_channels >= 2;
268 dsp_proc_activate(dsp, DSP_PROC_CROSSFEED, active);
269
270 if (active)
271 {
272 if (!was_active)
273 crossfeed_flush(this); /* Going online */
274
275 return PROC_NEW_FORMAT_OK;
276 }
277
278 /* Can't do this. Sleep until next change */
279 DEBUGF(" DSP_PROC_CROSSFEED- deactivated\n");
280 return PROC_NEW_FORMAT_DEACTIVATED;
281}
282
276/* DSP message hook */ 283/* DSP message hook */
277static intptr_t crossfeed_configure(struct dsp_proc_entry *this, 284static intptr_t crossfeed_configure(struct dsp_proc_entry *this,
278 struct dsp_config *dsp, 285 struct dsp_config *dsp,
279 unsigned int setting, 286 unsigned int setting,
280 intptr_t value) 287 intptr_t value)
281{ 288{
289 intptr_t retval = 0;
290
282 switch (setting) 291 switch (setting)
283 { 292 {
284 case DSP_PROC_INIT: 293 case DSP_PROC_INIT:
285 if (value == 0) 294 if (value == 0)
286 {
287 /* New object */
288 this->data = (intptr_t)&crossfeed_state; 295 this->data = (intptr_t)&crossfeed_state;
289 this->process[1] = crossfeed_process_new_format;
290 ((struct crossfeed_state *)this->data)->dsp = dsp;
291 }
292 296
293 /* Force format change call each time */ 297 update_process_fn(this, dsp);
294 this->process[0] = crossfeed_process_new_format;
295 dsp_proc_activate(dsp, DSP_PROC_CROSSFEED, true);
296 break; 298 break;
297 299
298 case DSP_FLUSH: 300 case DSP_FLUSH:
299 crossfeed_flush(this); 301 crossfeed_flush(this);
300 break; 302 break;
301 303
302 case DSP_PROC_CLOSE: 304 case DSP_PROC_NEW_FORMAT:
303 ((struct crossfeed_state *)this->data)->dsp = NULL; 305 retval = crossfeed_new_format(this, dsp,
306 (struct sample_format *)value);
304 break; 307 break;
305 } 308 }
306 309
307 return 1; 310 return retval;
308 (void)value;
309} 311}
310 312
311/* Database entry */ 313/* Database entry */
diff --git a/lib/rbcodec/dsp/dsp_core.c b/lib/rbcodec/dsp/dsp_core.c
index 84a23a4c83..c54bda17a9 100644
--- a/lib/rbcodec/dsp/dsp_core.c
+++ b/lib/rbcodec/dsp/dsp_core.c
@@ -34,6 +34,13 @@
34#define DSP_PROC_DB_CREATE 34#define DSP_PROC_DB_CREATE
35#include "dsp_proc_entry.h" 35#include "dsp_proc_entry.h"
36 36
37#ifndef DSP_PROCESS_START
38/* These do nothing if not previously defined */
39#define DSP_PROCESS_START()
40#define DSP_PROCESS_LOOP()
41#define DSP_PROCESS_END()
42#endif /* !DSP_PROCESS_START */
43
37/* Linked lists give fewer loads in processing loop compared to some index 44/* Linked lists give fewer loads in processing loop compared to some index
38 * list, which is more important than keeping occasionally executed code 45 * list, which is more important than keeping occasionally executed code
39 * simple */ 46 * simple */
@@ -41,24 +48,23 @@
41struct dsp_config 48struct dsp_config
42{ 49{
43 /** General DSP-local data **/ 50 /** General DSP-local data **/
44 struct sample_io_data io_data; /* Sample input-output data (first) */ 51 struct sample_io_data io_data; /* Sample input-output data (first) */
45 uint32_t slot_free_mask; /* Mask of free slots for this DSP */ 52 uint32_t slot_free_mask; /* Mask of free slots for this DSP */
46 uint32_t proc_masks[2]; /* Mask of active/enabled stages */ 53 uint32_t proc_mask_enabled; /* Mask of enabled stages */
54 uint32_t proc_mask_active; /* Mask of active stages */
47 struct dsp_proc_slot 55 struct dsp_proc_slot
48 { 56 {
49 struct dsp_proc_entry proc_entry; /* This enabled stage */ 57 struct dsp_proc_entry proc_entry; /* This enabled stage */
50 struct dsp_proc_slot *next[2]; /* [0]=active next, [1]=enabled next */ 58 struct dsp_proc_slot *next; /* Next enabled slot */
51 const struct dsp_proc_db_entry *db_entry; 59 uint32_t mask; /* In place operation mask/flag */
52 } *proc_slots[2]; /* Pointer to first in list of 60 uint8_t version; /* Sample format version */
53 active/enabled stages */ 61 uint8_t db_index; /* Index in database array */
54 62 } *proc_slots; /* Pointer to first in list of enabled
55 /** Misc. extra stuff **/ 63 stages */
56#if 0 /* Not needed now but enable if something must know this */
57 bool processing; /* DSP is processing (to thwart inopportune
58 buffer moves) */
59#endif
60}; 64};
61 65
66#define NACT_BIT BIT_N(___DSP_PROC_ID_RESERVED)
67
62/* Pool of slots for stages - supports 32 or fewer combined as-is atm. */ 68/* Pool of slots for stages - supports 32 or fewer combined as-is atm. */
63static struct dsp_proc_slot 69static struct dsp_proc_slot
64dsp_proc_slot_arr[DSP_NUM_PROC_STAGES+DSP_VOICE_NUM_PROC_STAGES] IBSS_ATTR; 70dsp_proc_slot_arr[DSP_NUM_PROC_STAGES+DSP_VOICE_NUM_PROC_STAGES] IBSS_ATTR;
@@ -67,6 +73,11 @@ dsp_proc_slot_arr[DSP_NUM_PROC_STAGES+DSP_VOICE_NUM_PROC_STAGES] IBSS_ATTR;
67static struct dsp_config dsp_conf[DSP_COUNT] IBSS_ATTR; 73static struct dsp_config dsp_conf[DSP_COUNT] IBSS_ATTR;
68 74
69/** Processing stages support functions **/ 75/** Processing stages support functions **/
76static const struct dsp_proc_db_entry *
77proc_db_entry(const struct dsp_proc_slot *s)
78{
79 return dsp_proc_database[s->db_index];
80}
70 81
71/* Find the slot for a given enabled id */ 82/* Find the slot for a given enabled id */
72static struct dsp_proc_slot * find_proc_slot(struct dsp_config *dsp, 83static struct dsp_proc_slot * find_proc_slot(struct dsp_config *dsp,
@@ -74,17 +85,17 @@ static struct dsp_proc_slot * find_proc_slot(struct dsp_config *dsp,
74{ 85{
75 const uint32_t mask = BIT_N(id); 86 const uint32_t mask = BIT_N(id);
76 87
77 if ((dsp->proc_masks[1] & mask) == 0) 88 if (!(dsp->proc_mask_enabled & mask))
78 return NULL; /* Not enabled */ 89 return NULL; /* Not enabled */
79 90
80 struct dsp_proc_slot *s = dsp->proc_slots[1]; 91 struct dsp_proc_slot *s = dsp->proc_slots;
81 92
82 while (1) /* In proc_masks == it must be there */ 93 while (1) /* In proc_mask_enabled == it must be there */
83 { 94 {
84 if (BIT_N(s->db_entry->id) == mask) 95 if (BIT_N(proc_db_entry(s)->id) == mask)
85 return s; 96 return s;
86 97
87 s = s->next[1]; 98 s = s->next;
88 } 99 }
89} 100}
90 101
@@ -94,54 +105,23 @@ static intptr_t proc_broadcast(struct dsp_config *dsp, unsigned int setting,
94 intptr_t value) 105 intptr_t value)
95{ 106{
96 bool multi = setting < DSP_PROC_SETTING; 107 bool multi = setting < DSP_PROC_SETTING;
97 struct dsp_proc_slot *s = multi ? 108 struct dsp_proc_slot *s = multi ? dsp->proc_slots :
98 dsp->proc_slots[1] : find_proc_slot(dsp, setting - DSP_PROC_SETTING); 109 find_proc_slot(dsp, setting - DSP_PROC_SETTING);
99 110
100 while (s != NULL) 111 while (s != NULL)
101 { 112 {
102 intptr_t ret = s->db_entry->configure(&s->proc_entry, dsp, setting, 113 intptr_t ret = proc_db_entry(s)->configure(
103 value); 114 &s->proc_entry, dsp, setting, value);
115
104 if (!multi) 116 if (!multi)
105 return ret; 117 return ret;
106 118
107 s = s->next[1]; 119 s = s->next;
108 } 120 }
109 121
110 return multi ? 1 : 0; 122 return multi ? 1 : 0;
111} 123}
112 124
113/* Generic handler for this->process[0] */
114static void dsp_process_null(struct dsp_proc_entry *this,
115 struct dsp_buffer **buf_p)
116{
117 (void)this; (void)buf_p;
118}
119
120/* Generic handler for this->process[1] */
121static void dsp_format_change_process(struct dsp_proc_entry *this,
122 struct dsp_buffer **buf_p)
123{
124 enum dsp_proc_ids id =
125 TYPE_FROM_MEMBER(struct dsp_proc_slot, this, proc_entry)->db_entry->id;
126
127 DSP_PRINT_FORMAT(<Default Handler>, id, (*buf_p)->format);
128
129 /* We don't keep back references to the DSP, so just search for it */
130 struct dsp_config *dsp;
131 for (unsigned int i = 0; (dsp = dsp_get_config(i)); i++)
132 {
133 /* Found one with the id, check if it's this one
134 (NULL return doesn't matter) */
135 if (&find_proc_slot(dsp, id)->proc_entry == this)
136 {
137 if (dsp_proc_active(dsp, id))
138 dsp_proc_call(this, buf_p, 0);
139
140 break;
141 }
142 }
143}
144
145/* Add an item to the enabled list */ 125/* Add an item to the enabled list */
146static struct dsp_proc_slot * 126static struct dsp_proc_slot *
147dsp_proc_enable_enlink(struct dsp_config *dsp, uint32_t mask) 127dsp_proc_enable_enlink(struct dsp_config *dsp, uint32_t mask)
@@ -156,44 +136,42 @@ dsp_proc_enable_enlink(struct dsp_config *dsp, uint32_t mask)
156 return NULL; 136 return NULL;
157 } 137 }
158 138
159 const struct dsp_proc_db_entry *db_entry_prev = NULL; 139 unsigned int db_index = 0, db_index_prev = DSP_NUM_PROC_STAGES;
160 const struct dsp_proc_db_entry *db_entry;
161 140
162 /* Order of enabled list is same as DB array */ 141 /* Order of enabled list is same as DB array */
163 for (unsigned int i = 0;; i++) 142 while (1)
164 { 143 {
165 if (i >= DSP_NUM_PROC_STAGES) 144 uint32_t m = BIT_N(dsp_proc_database[db_index]->id);
166 return NULL;
167
168 db_entry = dsp_proc_database[i];
169
170 uint32_t m = BIT_N(db_entry->id);
171 145
172 if (m == mask) 146 if (m == mask)
173 break; /* This is the one */ 147 break; /* This is the one */
174 148
175 if (dsp->proc_masks[1] & m) 149 if (dsp->proc_mask_enabled & m)
176 db_entry_prev = db_entry; 150 db_index_prev = db_index;
151
152 if (++db_index >= DSP_NUM_PROC_STAGES)
153 return NULL;
177 } 154 }
178 155
179 struct dsp_proc_slot *s = &dsp_proc_slot_arr[slot]; 156 struct dsp_proc_slot *s = &dsp_proc_slot_arr[slot];
180 157
181 if (db_entry_prev != NULL) 158 if (db_index_prev < DSP_NUM_PROC_STAGES)
182 { 159 {
183 struct dsp_proc_slot *prev = find_proc_slot(dsp, db_entry_prev->id); 160 struct dsp_proc_slot *prev =
184 s->next[0] = prev->next[0]; 161 find_proc_slot(dsp, dsp_proc_database[db_index_prev]->id);
185 s->next[1] = prev->next[1]; 162 s->next = prev->next;
186 prev->next[1] = s; 163 prev->next = s;
187 } 164 }
188 else 165 else
189 { 166 {
190 s->next[0] = dsp->proc_slots[0]; 167 s->next = dsp->proc_slots;
191 s->next[1] = dsp->proc_slots[1]; 168 dsp->proc_slots = s;
192 dsp->proc_slots[1] = s;
193 } 169 }
194 170
195 s->db_entry = db_entry; /* record DB entry */ 171 s->mask = mask | NACT_BIT;
196 dsp->proc_masks[1] |= mask; 172 s->version = 0;
173 s->db_index = db_index;
174 dsp->proc_mask_enabled |= mask;
197 dsp->slot_free_mask &= ~BIT_N(slot); 175 dsp->slot_free_mask &= ~BIT_N(slot);
198 176
199 return s; 177 return s;
@@ -203,33 +181,33 @@ dsp_proc_enable_enlink(struct dsp_config *dsp, uint32_t mask)
203static struct dsp_proc_slot * 181static struct dsp_proc_slot *
204dsp_proc_enable_delink(struct dsp_config *dsp, uint32_t mask) 182dsp_proc_enable_delink(struct dsp_config *dsp, uint32_t mask)
205{ 183{
206 struct dsp_proc_slot *s = dsp->proc_slots[1]; 184 struct dsp_proc_slot *s = dsp->proc_slots;
207 struct dsp_proc_slot *prev = NULL; 185 struct dsp_proc_slot *prev = NULL;
208 186
209 while (1) /* In proc_masks == it must be there */ 187 while (1) /* In proc_mask_enabled == it must be there */
210 { 188 {
211 if (BIT_N(s->db_entry->id) == mask) 189 if (BIT_N(proc_db_entry(s)->id) == mask)
212 { 190 {
213 if (prev) 191 if (prev)
214 prev->next[1] = s->next[1]; 192 prev->next = s->next;
215 else 193 else
216 dsp->proc_slots[1] = s->next[1]; 194 dsp->proc_slots = s->next;
217 195
218 dsp->proc_masks[1] &= ~mask; 196 dsp->proc_mask_enabled &= ~mask;
219 dsp->slot_free_mask |= BIT_N(s - dsp_proc_slot_arr); 197 dsp->slot_free_mask |= BIT_N(s - dsp_proc_slot_arr);
220 return s; 198 return s;
221 } 199 }
222 200
223 prev = s; 201 prev = s;
224 s = s->next[1]; 202 s = s->next;
225 } 203 }
226} 204}
227 205
228void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, 206void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id,
229 bool enable) 207 bool enable)
230{ 208{
231 uint32_t mask = BIT_N(id); 209 const uint32_t mask = BIT_N(id);
232 bool enabled = dsp->proc_masks[1] & mask; 210 bool enabled = dsp->proc_mask_enabled & mask;
233 211
234 if (enable) 212 if (enable)
235 { 213 {
@@ -247,13 +225,11 @@ void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id,
247 { 225 {
248 /* New entry - set defaults */ 226 /* New entry - set defaults */
249 s->proc_entry.data = 0; 227 s->proc_entry.data = 0;
250 s->proc_entry.ip_mask = mask; 228 s->proc_entry.process = NULL;
251 s->proc_entry.process[0] = dsp_process_null;
252 s->proc_entry.process[1] = dsp_format_change_process;
253 } 229 }
254 230
255 enabled = s->db_entry->configure(&s->proc_entry, dsp, DSP_PROC_INIT, 231 enabled = proc_db_entry(s)->configure(&s->proc_entry, dsp,
256 enabled) >= 0; 232 DSP_PROC_INIT, enabled) >= 0;
257 if (enabled) 233 if (enabled)
258 return; 234 return;
259 235
@@ -267,38 +243,7 @@ void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id,
267 243
268 dsp_proc_activate(dsp, id, false); /* Deactivate it first */ 244 dsp_proc_activate(dsp, id, false); /* Deactivate it first */
269 struct dsp_proc_slot *s = dsp_proc_enable_delink(dsp, mask); 245 struct dsp_proc_slot *s = dsp_proc_enable_delink(dsp, mask);
270 s->db_entry->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0); 246 proc_db_entry(s)->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0);
271}
272
273/* Maintain the list structure for the active list where each enabled entry
274 * has a link to the next active item, even if not active which facilitates
275 * switching out of format change mode by a stage during a format change.
276 * When that happens, the iterator must jump over inactive but enabled
277 * stages after its current position. */
278static struct dsp_proc_slot *
279dsp_proc_activate_link(struct dsp_config *dsp, uint32_t mask,
280 struct dsp_proc_slot *s)
281{
282 uint32_t m = BIT_N(s->db_entry->id);
283 uint32_t mor = m | mask;
284
285 if (mor == m) /* Only if same single bit in common */
286 {
287 dsp->proc_masks[0] |= mask;
288 return s;
289 }
290 else if (~mor == 0) /* Only if bits complement */
291 {
292 dsp->proc_masks[0] &= mask;
293 return s->next[0];
294 }
295
296 struct dsp_proc_slot *next = s->next[1];
297 next = dsp_proc_activate_link(dsp, mask, next);
298
299 s->next[0] = next;
300
301 return (m & dsp->proc_masks[0]) ? s : next;
302} 247}
303 248
304/* Activate or deactivate a stage */ 249/* Activate or deactivate a stage */
@@ -307,55 +252,109 @@ void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id,
307{ 252{
308 const uint32_t mask = BIT_N(id); 253 const uint32_t mask = BIT_N(id);
309 254
310 if (!(dsp->proc_masks[1] & mask)) 255 if (!(dsp->proc_mask_enabled & mask))
311 return; /* Not enabled */ 256 return; /* Not enabled */
312 257
313 if (activate != !(dsp->proc_masks[0] & mask)) 258 if (activate != !(dsp->proc_mask_active & mask))
314 return; /* No change in state */ 259 return; /* No change in state */
315 260
316 /* Send mask bit if activating and ones complement if deactivating */ 261 struct dsp_proc_slot *s = find_proc_slot(dsp, id);
317 dsp->proc_slots[0] = dsp_proc_activate_link( 262
318 dsp, activate ? mask : ~mask, dsp->proc_slots[1]); 263 if (activate)
264 {
265 dsp->proc_mask_active |= mask;
266 s->mask &= ~NACT_BIT;
267 }
268 else
269 {
270 dsp->proc_mask_active &= ~mask;
271 s->mask |= NACT_BIT;
272 }
319} 273}
320 274
321/* Is the stage specified by the id currently active? */ 275/* Is the stage specified by the id currently active? */
322bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id) 276bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id)
323{ 277{
324 return (dsp->proc_masks[0] & BIT_N(id)) != 0; 278 return (dsp->proc_mask_active & BIT_N(id)) != 0;
325} 279}
326 280
327/* Determine by the rules if the processing function should be called */ 281/* Force the specified stage to receive a format update before the next
328static FORCE_INLINE bool dsp_proc_should_call(struct dsp_proc_entry *this, 282 * buffer is sent to process() */
329 struct dsp_buffer *buf, 283void dsp_proc_want_format_update(struct dsp_config *dsp,
330 unsigned int fmt) 284 enum dsp_proc_ids id)
331{ 285{
332 uint32_t ip_mask = this->ip_mask; 286 struct dsp_proc_slot *s = find_proc_slot(dsp, id);
333 287
334 return UNLIKELY(fmt != 0) || /* Also pass override value */ 288 if (s)
335 ip_mask == 0 || /* Not in-place */ 289 s->version = 0; /* Set invalid */
336 ((ip_mask & buf->proc_mask) == 0 &&
337 (buf->proc_mask |= ip_mask, buf->remcount > 0));
338} 290}
339 291
340/* Call this->process[fmt] according to the rules (for external call) */ 292/* Set or unset in-place operation */
341bool dsp_proc_call(struct dsp_proc_entry *this, struct dsp_buffer **buf_p, 293void dsp_proc_set_in_place(struct dsp_config *dsp, enum dsp_proc_ids id,
342 unsigned int fmt) 294 bool in_place)
343{ 295{
344 if (dsp_proc_should_call(this, *buf_p, fmt)) 296 struct dsp_proc_slot *s = find_proc_slot(dsp, id);
297
298 if (!s)
299 return;
300
301 const uint32_t mask = BIT_N(id);
302
303 if (in_place)
304 s->mask |= mask;
305 else
306 s->mask &= ~mask;
307}
308
309/* Determine by the rules if the processing function should be called */
310static NO_INLINE bool dsp_proc_new_format(struct dsp_proc_slot *s,
311 struct dsp_config *dsp,
312 struct dsp_buffer *buf)
313{
314 struct dsp_proc_entry *this = &s->proc_entry;
315 struct sample_format *format = &buf->format;
316
317 switch (proc_db_entry(s)->configure(
318 this, dsp, DSP_PROC_NEW_FORMAT, (intptr_t)format))
345 { 319 {
346 this->process[fmt == (0u-1u) ? 0 : fmt](this, buf_p); 320 case PROC_NEW_FORMAT_OK:
321 s->version = format->version;
347 return true; 322 return true;
348 }
349 323
350 return false; 324 case PROC_NEW_FORMAT_TRANSITION:
325 return true;
326
327 case PROC_NEW_FORMAT_DEACTIVATED:
328 s->version = format->version;
329 return false;
330
331 default:
332 return false;
333 }
351} 334}
352 335
353#ifndef DSP_PROCESS_START 336static FORCE_INLINE void dsp_proc_call(struct dsp_proc_slot *s,
354/* These do nothing if not previously defined */ 337 struct dsp_config *dsp,
355#define DSP_PROCESS_START() 338 struct dsp_buffer **buf_p)
356#define DSP_PROCESS_LOOP() 339{
357#define DSP_PROCESS_END() 340 struct dsp_buffer *buf = *buf_p;
358#endif /* !DSP_PROCESS_START */ 341
342 if (UNLIKELY(buf->format.version != s->version))
343 {
344 if (!dsp_proc_new_format(s, dsp, buf))
345 return;
346 }
347
348 if (s->mask)
349 {
350 if ((s->mask & (buf->proc_mask | NACT_BIT)) || buf->remcount <= 0)
351 return;
352
353 buf->proc_mask |= s->mask;
354 }
355
356 s->proc_entry.process(&s->proc_entry, buf_p);
357}
359 358
360/** 359/**
361 * dsp_process: 360 * dsp_process:
@@ -411,9 +410,6 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src,
411 } 410 }
412 411
413 DSP_PROCESS_START(); 412 DSP_PROCESS_START();
414#if 0 /* Not needed now but enable if something must know this */
415 dsp->processing = true;
416#endif
417 413
418 /* Tag input with codec-specified sample format */ 414 /* Tag input with codec-specified sample format */
419 src->format = dsp->io_data.format; 415 src->format = dsp->io_data.format;
@@ -423,36 +419,29 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src,
423 /* Out-of-place-processing stages take the current buf as input 419 /* Out-of-place-processing stages take the current buf as input
424 * and switch the buffer to their own output buffer */ 420 * and switch the buffer to their own output buffer */
425 struct dsp_buffer *buf = src; 421 struct dsp_buffer *buf = src;
426 unsigned int fmt = buf->format.changed;
427 422
428 /* Convert input samples to internal format */ 423 if (UNLIKELY(buf->format.version != dsp->io_data.sample_buf.format.version))
429 dsp->io_data.input_samples[fmt](&dsp->io_data, &buf); 424 dsp_sample_input_format_change(&dsp->io_data, &buf->format);
430 fmt = buf->format.changed;
431 425
432 struct dsp_proc_slot *s = dsp->proc_slots[fmt]; 426 /* Convert input samples to internal format */
427 dsp->io_data.input_samples(&dsp->io_data, &buf);
433 428
434 /* Call all active/enabled stages depending if format is 429 /* Call all active/enabled stages depending if format is
435 same/changed on the last output buffer */ 430 same/changed on the last output buffer */
436 while (s != NULL) 431 for (struct dsp_proc_slot *s = dsp->proc_slots; s; s = s->next)
437 { 432 dsp_proc_call(s, dsp, &buf);
438 if (dsp_proc_should_call(&s->proc_entry, buf, fmt))
439 {
440 s->proc_entry.process[fmt](&s->proc_entry, &buf);
441 fmt = buf->format.changed;
442 }
443
444 /* The buffer may have changed along with the format flag */
445 s = s->next[fmt];
446 }
447 433
448 /* Don't overread/write src/destination */ 434 /* Don't overread/write src/destination */
449 int outcount = MIN(dst->bufcount, buf->remcount); 435 int outcount = MIN(dst->bufcount, buf->remcount);
450 436
451 if (fmt == 0 && outcount <= 0) 437 if (outcount <= 0)
452 break; /* Output full or purged internal buffers */ 438 break; /* Output full or purged internal buffers */
453 439
440 if (UNLIKELY(buf->format.version != dsp->io_data.output_version))
441 dsp_sample_output_format_change(&dsp->io_data, &buf->format);
442
454 dsp->io_data.outcount = outcount; 443 dsp->io_data.outcount = outcount;
455 dsp->io_data.output_samples[fmt](&dsp->io_data, buf, dst); 444 dsp->io_data.output_samples(&dsp->io_data, buf, dst);
456 445
457 /* Advance buffers by what output consumed and produced */ 446 /* Advance buffers by what output consumed and produced */
458 dsp_advance_buffer32(buf, outcount); 447 dsp_advance_buffer32(buf, outcount);
@@ -461,10 +450,6 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src,
461 DSP_PROCESS_LOOP(); 450 DSP_PROCESS_LOOP();
462 } /* while */ 451 } /* while */
463 452
464#if 0 /* Not needed now but enable if something must know this */
465 dsp->process = false;
466#endif
467
468 DSP_PROCESS_END(); 453 DSP_PROCESS_END();
469} 454}
470 455
@@ -495,13 +480,6 @@ enum dsp_ids dsp_get_id(const struct dsp_config *dsp)
495 return (enum dsp_ids)id; 480 return (enum dsp_ids)id;
496} 481}
497 482
498#if 0 /* Not needed now but enable if something must know this */
499bool dsp_is_busy(const struct dsp_config *dsp)
500{
501 return dsp->processing;
502}
503#endif /* 0 */
504
505/* Do what needs initializing before enable/disable calls can be made. 483/* Do what needs initializing before enable/disable calls can be made.
506 * Must be done before changing settings for the first time. */ 484 * Must be done before changing settings for the first time. */
507void INIT_ATTR dsp_init(void) 485void INIT_ATTR dsp_init(void)
diff --git a/lib/rbcodec/dsp/dsp_core.h b/lib/rbcodec/dsp/dsp_core.h
index 0119da8af6..713190debc 100644
--- a/lib/rbcodec/dsp/dsp_core.h
+++ b/lib/rbcodec/dsp/dsp_core.h
@@ -39,8 +39,10 @@ enum dsp_settings
39 DSP_SET_SAMPLE_DEPTH, 39 DSP_SET_SAMPLE_DEPTH,
40 DSP_SET_STEREO_MODE, 40 DSP_SET_STEREO_MODE,
41 DSP_FLUSH, 41 DSP_FLUSH,
42 DSP_SET_PITCH,
42 DSP_PROC_INIT, 43 DSP_PROC_INIT,
43 DSP_PROC_CLOSE, 44 DSP_PROC_CLOSE,
45 DSP_PROC_NEW_FORMAT,
44 DSP_PROC_SETTING, /* stage-specific should be this + id */ 46 DSP_PROC_SETTING, /* stage-specific should be this + id */
45}; 47};
46 48
@@ -54,10 +56,13 @@ enum dsp_stereo_modes
54 STEREO_NUM_MODES, 56 STEREO_NUM_MODES,
55}; 57};
56 58
57/* Format into for the buffer (if .valid == true) */ 59/* Format into for the buffer */
58struct sample_format 60struct sample_format
59{ 61{
60 uint8_t changed; /* 00h: 0=no change, 1=changed (is also index) */ 62 uint8_t version; /* 00h: format version number (never == 0,
63 0 is used to detect format calls for
64 individual stages, such as when they
65 are newly enabled) */
61 uint8_t num_channels; /* 01h: number of channels of data */ 66 uint8_t num_channels; /* 01h: number of channels of data */
62 uint8_t frac_bits; /* 02h: number of fractional bits */ 67 uint8_t frac_bits; /* 02h: number of fractional bits */
63 uint8_t output_scale; /* 03h: output scaling shift */ 68 uint8_t output_scale; /* 03h: output scaling shift */
@@ -66,16 +71,6 @@ struct sample_format
66 /* 0ch */ 71 /* 0ch */
67}; 72};
68 73
69/* Compare format data only */
70#define EQU_SAMPLE_FORMAT(f1, f2) \
71 (!memcmp(&(f1).num_channels, &(f2).num_channels, \
72 sizeof (f1) - sizeof ((f1).changed)))
73
74static inline void format_change_set(struct sample_format *f)
75 { f->changed = 1; }
76static inline void format_change_ack(struct sample_format *f)
77 { f->changed = 0; }
78
79/* Used by ASM routines - keep field order or else fix the functions */ 74/* Used by ASM routines - keep field order or else fix the functions */
80struct dsp_buffer 75struct dsp_buffer
81{ 76{
@@ -133,30 +128,12 @@ static inline void dsp_advance_buffer32(struct dsp_buffer *buf,
133 buf->p32[1] += by_count; 128 buf->p32[1] += by_count;
134} 129}
135 130
136/** For use by processing stages **/
137
138#define DSP_PRINT_FORMAT(name, id, format) \
139 DEBUGF("DSP format- " #name "\n" \
140 " id:%d chg:%c ch:%u fb:%u os:%u hz:%u chz:%u\n", \
141 (int)id, \
142 (format).changed ? 'y' : 'n', \
143 (unsigned int)(format).num_channels, \
144 (unsigned int)(format).frac_bits, \
145 (unsigned int)(format).output_scale, \
146 (unsigned int)(format).frequency, \
147 (unsigned int)(format).codec_frequency);
148
149/* Get DSP pointer */ 131/* Get DSP pointer */
150struct dsp_config * dsp_get_config(enum dsp_ids id); 132struct dsp_config * dsp_get_config(enum dsp_ids id);
151 133
152/* Get DSP id */ 134/* Get DSP id */
153enum dsp_ids dsp_get_id(const struct dsp_config *dsp); 135enum dsp_ids dsp_get_id(const struct dsp_config *dsp);
154 136
155#if 0 /* Not needed now but enable if something must know this */
156/* Is the DSP processing a buffer? */
157bool dsp_is_busy(const struct dsp_config *dsp);
158#endif /* 0 */
159
160/** General DSP processing **/ 137/** General DSP processing **/
161 138
162/* Process the given buffer - see implementation in dsp.c for more */ 139/* Process the given buffer - see implementation in dsp.c for more */
diff --git a/lib/rbcodec/dsp/dsp_misc.c b/lib/rbcodec/dsp/dsp_misc.c
index 672212b267..a19ef52883 100644
--- a/lib/rbcodec/dsp/dsp_misc.c
+++ b/lib/rbcodec/dsp/dsp_misc.c
@@ -26,7 +26,6 @@
26#include "fixedpoint.h" 26#include "fixedpoint.h"
27#include "replaygain.h" 27#include "replaygain.h"
28#include "dsp_proc_entry.h" 28#include "dsp_proc_entry.h"
29#include "dsp_sample_io.h"
30#include "dsp_misc.h" 29#include "dsp_misc.h"
31#include "pga.h" 30#include "pga.h"
32#include "channel_mode.h" 31#include "channel_mode.h"
@@ -113,20 +112,21 @@ static int32_t pitch_ratio = PITCH_SPEED_100;
113 112
114static void dsp_pitch_update(struct dsp_config *dsp) 113static void dsp_pitch_update(struct dsp_config *dsp)
115{ 114{
116 /* Account for playback speed adjustment when setting dsp->frequency 115 dsp_configure(dsp, DSP_SET_PITCH,
117 if we're called from the main audio thread. Voice playback thread 116 fp_div(pitch_ratio, PITCH_SPEED_100, 16));
118 does not support this feature. */
119 struct sample_io_data *data = (void *)dsp;
120 data->format.frequency =
121 (int64_t)pitch_ratio * data->format.codec_frequency / PITCH_SPEED_100;
122} 117}
123 118
124static void dsp_set_pitch(int32_t percent) 119static void dsp_set_pitch(int32_t percent)
125{ 120{
126 pitch_ratio = percent > 0 ? percent : PITCH_SPEED_100; 121 if (percent <= 0)
127 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); 122 percent = PITCH_SPEED_100;
128 struct sample_io_data *data = (void *)dsp; 123
129 dsp_configure(dsp, DSP_SWITCH_FREQUENCY, data->format.codec_frequency); 124 if (percent == pitch_ratio)
125 return;
126
127 pitch_ratio = percent;
128
129 dsp_pitch_update(dsp_get_config(CODEC_IDX_AUDIO));
130} 130}
131#endif /* HAVE_PITCHCONTROL */ 131#endif /* HAVE_PITCHCONTROL */
132 132
@@ -173,6 +173,13 @@ int dsp_callback(int msg, intptr_t param)
173 return retval; 173 return retval;
174} 174}
175 175
176static void INIT_ATTR misc_dsp_init(struct dsp_config *dsp,
177 enum dsp_ids dsp_id)
178{
179 /* Enable us for the audio DSP at startup */
180 if (dsp_id == CODEC_IDX_AUDIO)
181 dsp_proc_enable(dsp, DSP_PROC_MISC_HANDLER, true);
182}
176 183
177/* This is a null-processing stage that monitors as an enabled stage but never 184/* This is a null-processing stage that monitors as an enabled stage but never
178 * becomes active in processing samples. It only hooks messages. */ 185 * becomes active in processing samples. It only hooks messages. */
@@ -186,9 +193,7 @@ static intptr_t misc_handler_configure(struct dsp_proc_entry *this,
186 switch (setting) 193 switch (setting)
187 { 194 {
188 case DSP_INIT: 195 case DSP_INIT:
189 /* Enable us for the audio DSP at startup */ 196 misc_dsp_init(dsp, (enum dsp_ids)value);
190 if (value == CODEC_IDX_AUDIO)
191 dsp_proc_enable(dsp, DSP_PROC_MISC_HANDLER, true);
192 break; 197 break;
193 198
194 case DSP_PROC_CLOSE: 199 case DSP_PROC_CLOSE:
@@ -212,7 +217,7 @@ static intptr_t misc_handler_configure(struct dsp_proc_entry *this,
212#endif 217#endif
213 } 218 }
214 219
215 return 1; 220 return 0;
216 (void)this; 221 (void)this;
217} 222}
218 223
diff --git a/lib/rbcodec/dsp/dsp_proc_entry.h b/lib/rbcodec/dsp/dsp_proc_entry.h
index c53443713b..902385f08d 100644
--- a/lib/rbcodec/dsp/dsp_proc_entry.h
+++ b/lib/rbcodec/dsp/dsp_proc_entry.h
@@ -79,7 +79,7 @@ struct dsp_proc_db_entry;
79#define DSP_PROC_DB_START \ 79#define DSP_PROC_DB_START \
80 enum dsp_proc_ids \ 80 enum dsp_proc_ids \
81 { \ 81 { \
82 ___DSP_PROC_ID_FIRST = -1, 82 ___DSP_PROC_ID_RESERVED = 0,
83 83
84#define DSP_PROC_DB_ITEM(name) \ 84#define DSP_PROC_DB_ITEM(name) \
85 DSP_PROC_##name, 85 DSP_PROC_##name,
@@ -102,19 +102,24 @@ typedef void (*dsp_proc_fn_type)(struct dsp_proc_entry *this,
102 * The structure allocated to every stage when enabled. 102 * The structure allocated to every stage when enabled.
103 * 103 *
104 * default settings: 104 * default settings:
105 * .data = 0 105 * .data = 0
106 * .ip_mask = BIT_N(dsp_proc_db_entry.id) 106 * .process = NULL
107 * .process[0] = dsp_process_null
108 * .process[1] = dsp_format_change_process
109 * 107 *
110 * DSP_PROC_INIT handler just has to change what it needs to change. It may 108 * DSP_PROC_INIT handler just has to change what it needs to change. It may
111 * also be modified at any time to implement the stage's demands. 109 * also be modified at any time to implement the stage's demands.
112 */ 110 */
113struct dsp_proc_entry 111struct dsp_proc_entry
114{ 112{
115 intptr_t data; /* 00h: any value, at beginning for easy asm use */ 113 intptr_t data; /* 00h: any value, used by asm */
116 uint32_t ip_mask; /* In-place id bit (0 or id bit flag if in-place) */ 114 dsp_proc_fn_type process; /* Processing vector */
117 dsp_proc_fn_type process[2]; /* Processing normal/format changes */ 115};
116
117/* Return values for DSP_PROC_NEW_FORMAT setting */
118enum
119{
120 PROC_NEW_FORMAT_OK = 0, /* Acks, calls process() (default) */
121 PROC_NEW_FORMAT_DEACTIVATED, /* Acks, does not call process() */
122 PROC_NEW_FORMAT_TRANSITION /* Does not ack, calls process() */
118}; 123};
119 124
120/* DSP transform configure function prototype */ 125/* DSP transform configure function prototype */
@@ -137,10 +142,24 @@ void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id,
137/* Is the specified stage active on the DSP? */ 142/* Is the specified stage active on the DSP? */
138bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id); 143bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id);
139 144
140/* Call this->process[fmt] according to the rules 145/* Force the specified stage to receive a format update before the next
141 * pass (unsigned)-1 to call function 0 with no restriction */ 146 * buffer is sent to process() */
142bool dsp_proc_call(struct dsp_proc_entry *this, struct dsp_buffer **buf_p, 147void dsp_proc_want_format_update(struct dsp_config *dsp,
143 unsigned int fmt); 148 enum dsp_proc_ids id);
149
150/* Set or unset in-place operation */
151void dsp_proc_set_in_place(struct dsp_config *dsp, enum dsp_proc_ids id,
152 bool in_place);
153
154#define DSP_PRINT_FORMAT(id, format) \
155 DEBUGF("DSP format- " #id "\n" \
156 " ver:%u ch:%u fb:%u os:%u hz:%u chz:%u\n", \
157 (unsigned int)(format).version \
158 (unsigned int)(format).num_channels, \
159 (unsigned int)(format).frac_bits, \
160 (unsigned int)(format).output_scale, \
161 (unsigned int)(format).frequency, \
162 (unsigned int)(format).codec_frequency);
144 163
145struct dsp_proc_db_entry 164struct dsp_proc_db_entry
146{ 165{
diff --git a/lib/rbcodec/dsp/dsp_sample_input.c b/lib/rbcodec/dsp/dsp_sample_input.c
index 284f34c96a..65d2a110e1 100644
--- a/lib/rbcodec/dsp/dsp_sample_input.c
+++ b/lib/rbcodec/dsp/dsp_sample_input.c
@@ -21,12 +21,12 @@
21 ****************************************************************************/ 21 ****************************************************************************/
22#include "config.h" 22#include "config.h"
23#include "system.h" 23#include "system.h"
24#include "fixedpoint.h"
24#include "dsp_core.h" 25#include "dsp_core.h"
25#include "dsp_sample_io.h" 26#include "dsp_sample_io.h"
27#include "dsp_proc_entry.h"
26 28
27#if 1 29#if 0
28#include <debug.h>
29#else
30#undef DEBUGF 30#undef DEBUGF
31#define DEBUGF(...) 31#define DEBUGF(...)
32#endif 32#endif
@@ -50,6 +50,8 @@
50 50
51extern void dsp_sample_output_init(struct sample_io_data *this); 51extern void dsp_sample_output_init(struct sample_io_data *this);
52extern void dsp_sample_output_flush(struct sample_io_data *this); 52extern void dsp_sample_output_flush(struct sample_io_data *this);
53extern void dsp_sample_output_format_change(struct sample_io_data *this,
54 struct sample_format *format);
53 55
54#define SAMPLE_BUF_COUNT 128 /* Per channel, per DSP */ 56#define SAMPLE_BUF_COUNT 128 /* Per channel, per DSP */
55/* CODEC_IDX_AUDIO = left and right, CODEC_IDX_VOICE = mono */ 57/* CODEC_IDX_AUDIO = left and right, CODEC_IDX_VOICE = mono */
@@ -75,8 +77,8 @@ static FORCE_INLINE int sample_input_setup(struct sample_io_data *this,
75 int count = MIN(s->remcount, SAMPLE_BUF_COUNT); 77 int count = MIN(s->remcount, SAMPLE_BUF_COUNT);
76 78
77 d->remcount = count; 79 d->remcount = count;
78 d->p32[0] = this->sample_buf_arr[0]; 80 d->p32[0] = this->sample_buf_p[0];
79 d->p32[1] = this->sample_buf_arr[channels - 1]; 81 d->p32[1] = this->sample_buf_p[channels - 1];
80 d->proc_mask = s->proc_mask; 82 d->proc_mask = s->proc_mask;
81 83
82 return count; 84 return count;
@@ -210,9 +212,9 @@ static void sample_input_ni_stereo32(struct sample_io_data *this,
210} 212}
211 213
212/* set the to-native sample conversion function based on dsp sample 214/* set the to-native sample conversion function based on dsp sample
213 * parameters */ 215 * parameters - depends upon stereo_mode and sample_depth */
214static void dsp_sample_input_format_change(struct sample_io_data *this, 216void dsp_sample_input_format_change(struct sample_io_data *this,
215 struct dsp_buffer **buf_p) 217 struct sample_format *format)
216{ 218{
217 static const sample_input_fn_type fns[STEREO_NUM_MODES][2] = 219 static const sample_input_fn_type fns[STEREO_NUM_MODES][2] =
218 { 220 {
@@ -227,33 +229,35 @@ static void dsp_sample_input_format_change(struct sample_io_data *this,
227 sample_input_mono32 }, 229 sample_input_mono32 },
228 }; 230 };
229 231
230 struct dsp_buffer *src = *buf_p; 232 if (this->sample_buf.remcount > 0)
231 struct dsp_buffer *dst = &this->sample_buf; 233 return;
232
233 /* Ack configured format change */
234 format_change_ack(&this->format);
235 234
236 if (dst->remcount > 0) 235 DSP_PRINT_FORMAT(DSP Input, this->format);
237 {
238 *buf_p = dst;
239 return; /* data still remains */
240 }
241 236
242 DSP_PRINT_FORMAT(DSP Input, -1, src->format); 237 this->format_dirty = 0;
238 this->sample_buf.format = *format;
239 this->input_samples = fns[this->stereo_mode]
240 [this->sample_depth > NATIVE_DEPTH ? 1 : 0];
241}
243 242
244 /* new format - remember it and pass it along */ 243/* increment the format version counter */
245 dst->format = src->format; 244static void format_change_set(struct sample_io_data *this)
246 this->input_samples[0] = fns[this->stereo_mode] 245{
247 [this->sample_depth > NATIVE_DEPTH ? 1 : 0]; 246 if (this->format_dirty)
247 return;
248 248
249 this->input_samples[0](this, buf_p); 249 this->format.version = (uint8_t)(this->format.version + 1) ?: 1;
250 this->format_dirty = 1;
251}
250 252
251 if (*buf_p == dst) /* buffer switch? */ 253/* discard the sample buffer */
252 format_change_ack(&src->format); 254static void dsp_sample_input_flush(struct sample_io_data *this)
255{
256 this->sample_buf.remcount = 0;
253} 257}
254 258
255static void dsp_sample_input_init(struct sample_io_data *this, 259static void INIT_ATTR dsp_sample_input_init(struct sample_io_data *this,
256 enum dsp_ids dsp_id) 260 enum dsp_ids dsp_id)
257{ 261{
258 int32_t *lbuf, *rbuf; 262 int32_t *lbuf, *rbuf;
259 263
@@ -274,17 +278,15 @@ static void dsp_sample_input_init(struct sample_io_data *this,
274 return; 278 return;
275 } 279 }
276 280
277 this->sample_buf_arr[0] = lbuf; 281 this->sample_buf_p[0] = lbuf;
278 this->sample_buf_arr[1] = rbuf; 282 this->sample_buf_p[1] = rbuf;
279
280 this->input_samples[0] = sample_input_ni_stereo32;
281 this->input_samples[1] = dsp_sample_input_format_change;
282} 283}
283 284
284/* discard the sample buffer */ 285static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this,
285static void dsp_sample_input_flush(struct sample_io_data *this) 286 enum dsp_ids dsp_id)
286{ 287{
287 this->sample_buf.remcount = 0; 288 dsp_sample_input_init(this, dsp_id);
289 dsp_sample_output_init(this);
288} 290}
289 291
290void dsp_sample_io_configure(struct sample_io_data *this, 292void dsp_sample_io_configure(struct sample_io_data *this,
@@ -294,13 +296,12 @@ void dsp_sample_io_configure(struct sample_io_data *this,
294 switch (setting) 296 switch (setting)
295 { 297 {
296 case DSP_INIT: 298 case DSP_INIT:
297 dsp_sample_input_init(this, (enum dsp_ids)value); 299 dsp_sample_io_init(this, (enum dsp_ids)value);
298 dsp_sample_output_init(this);
299 break; 300 break;
300 301
301 case DSP_RESET: 302 case DSP_RESET:
302 /* Reset all sample descriptions to default */ 303 /* Reset all sample descriptions to default */
303 format_change_set(&this->format); 304 format_change_set(this);
304 this->format.num_channels = 2; 305 this->format.num_channels = 2;
305 this->format.frac_bits = WORD_FRACBITS; 306 this->format.frac_bits = WORD_FRACBITS;
306 this->format.output_scale = WORD_FRACBITS + 1 - NATIVE_DEPTH; 307 this->format.output_scale = WORD_FRACBITS + 1 - NATIVE_DEPTH;
@@ -311,14 +312,14 @@ void dsp_sample_io_configure(struct sample_io_data *this,
311 break; 312 break;
312 313
313 case DSP_SET_FREQUENCY: 314 case DSP_SET_FREQUENCY:
315 format_change_set(this);
314 value = value > 0 ? value : NATIVE_FREQUENCY; 316 value = value > 0 ? value : NATIVE_FREQUENCY;
315 format_change_set(&this->format);
316 this->format.frequency = value; 317 this->format.frequency = value;
317 this->format.codec_frequency = value; 318 this->format.codec_frequency = value;
318 break; 319 break;
319 320
320 case DSP_SET_SAMPLE_DEPTH: 321 case DSP_SET_SAMPLE_DEPTH:
321 format_change_set(&this->format); 322 format_change_set(this);
322 this->format.frac_bits = 323 this->format.frac_bits =
323 value <= NATIVE_DEPTH ? WORD_FRACBITS : value; 324 value <= NATIVE_DEPTH ? WORD_FRACBITS : value;
324 this->format.output_scale = 325 this->format.output_scale =
@@ -327,7 +328,7 @@ void dsp_sample_io_configure(struct sample_io_data *this,
327 break; 328 break;
328 329
329 case DSP_SET_STEREO_MODE: 330 case DSP_SET_STEREO_MODE:
330 format_change_set(&this->format); 331 format_change_set(this);
331 this->format.num_channels = value == STEREO_MONO ? 1 : 2; 332 this->format.num_channels = value == STEREO_MONO ? 1 : 2;
332 this->stereo_mode = value; 333 this->stereo_mode = value;
333 break; 334 break;
@@ -336,5 +337,12 @@ void dsp_sample_io_configure(struct sample_io_data *this,
336 dsp_sample_input_flush(this); 337 dsp_sample_input_flush(this);
337 dsp_sample_output_flush(this); 338 dsp_sample_output_flush(this);
338 break; 339 break;
340
341 case DSP_SET_PITCH:
342 format_change_set(this);
343 value = value > 0 ? value : (1 << 16);
344 this->format.frequency =
345 fp_mul(value, this->format.codec_frequency, 16);
346 break;
339 } 347 }
340} 348}
diff --git a/lib/rbcodec/dsp/dsp_sample_io.h b/lib/rbcodec/dsp/dsp_sample_io.h
index 0afe75c6ca..22b7a4a3f4 100644
--- a/lib/rbcodec/dsp/dsp_sample_io.h
+++ b/lib/rbcodec/dsp/dsp_sample_io.h
@@ -42,16 +42,25 @@ typedef void (*sample_output_fn_type)(struct sample_io_data *this,
42/* This becomes part of the DSP aggregate */ 42/* This becomes part of the DSP aggregate */
43struct sample_io_data 43struct sample_io_data
44{ 44{
45 int outcount; /* 00h: Output count */ 45 int outcount; /* 00h: Output count */
46 struct sample_format format; /* General format info */ 46 struct sample_format format; /* Format for next dsp_process call */
47 int sample_depth; /* Codec-specified sample depth */ 47 int sample_depth; /* Codec-specified sample depth */
48 int stereo_mode; /* Codec-specified input format */ 48 int stereo_mode; /* Codec-specified channel format */
49 sample_input_fn_type input_samples[2]; /* input functions */ 49 sample_input_fn_type input_samples; /* Initial input function */
50 struct dsp_buffer sample_buf; /* Buffer descriptor for converted samples */ 50 struct dsp_buffer sample_buf; /* Buffer descriptor for converted samples */
51 int32_t *sample_buf_arr[2]; /* Internal format buffer pointers */ 51 int32_t *sample_buf_p[2]; /* Internal format buffer pointers */
52 sample_output_fn_type output_samples[2]; /* Final output functions */ 52 sample_output_fn_type output_samples; /* Final output function */
53 uint8_t format_dirty; /* Format change set, avoids superfluous
54 increments before carrying it out */
55 uint8_t output_version; /* Format version of src buffer at output */
53}; 56};
54 57
58void dsp_sample_input_format_change(struct sample_io_data *this,
59 struct sample_format *format);
60
61void dsp_sample_output_format_change(struct sample_io_data *this,
62 struct sample_format *format);
63
55/* Sample IO watches the format setting from the codec */ 64/* Sample IO watches the format setting from the codec */
56void dsp_sample_io_configure(struct sample_io_data *this, 65void dsp_sample_io_configure(struct sample_io_data *this,
57 unsigned int setting, 66 unsigned int setting,
diff --git a/lib/rbcodec/dsp/dsp_sample_output.c b/lib/rbcodec/dsp/dsp_sample_output.c
index 4a8050b082..d57d236cbb 100644
--- a/lib/rbcodec/dsp/dsp_sample_output.c
+++ b/lib/rbcodec/dsp/dsp_sample_output.c
@@ -23,6 +23,7 @@
23#include "system.h" 23#include "system.h"
24#include "dsp_core.h" 24#include "dsp_core.h"
25#include "dsp_sample_io.h" 25#include "dsp_sample_io.h"
26#include "dsp_proc_entry.h"
26#include "dsp-util.h" 27#include "dsp-util.h"
27#include <string.h> 28#include <string.h>
28 29
@@ -159,9 +160,8 @@ void sample_output_dithered(struct sample_io_data *this,
159} 160}
160 161
161/* Initialize the output function for settings and format */ 162/* Initialize the output function for settings and format */
162static void dsp_sample_output_format_change(struct sample_io_data *this, 163void dsp_sample_output_format_change(struct sample_io_data *this,
163 struct dsp_buffer *src, 164 struct sample_format *format)
164 struct dsp_buffer *dst)
165{ 165{
166 static const sample_output_fn_type fns[2][2] = 166 static const sample_output_fn_type fns[2][2] =
167 { 167 {
@@ -171,25 +171,20 @@ static void dsp_sample_output_format_change(struct sample_io_data *this,
171 sample_output_dithered }, 171 sample_output_dithered },
172 }; 172 };
173 173
174 struct sample_format *format = &src->format;
175 bool dither = dsp_get_id((void *)this) == CODEC_IDX_AUDIO && 174 bool dither = dsp_get_id((void *)this) == CODEC_IDX_AUDIO &&
176 dither_data.enabled; 175 dither_data.enabled;
177 int channels = format->num_channels; 176 int channels = format->num_channels;
178 177
179 DSP_PRINT_FORMAT(DSP Output, -1, *format); 178 DSP_PRINT_FORMAT(DSP Output, *format);
180 179
181 this->output_samples[0] = fns[dither ? 1 : 0][channels - 1]; 180 this->output_samples = fns[dither ? 1 : 0][channels - 1];
182 format_change_ack(format); /* always ack, we're last */ 181 this->output_version = format->version;
183
184 /* The real function mustn't be called with no data */
185 if (this->outcount > 0)
186 this->output_samples[0](this, src, dst);
187} 182}
188 183
189void dsp_sample_output_init(struct sample_io_data *this) 184void INIT_ATTR dsp_sample_output_init(struct sample_io_data *this)
190{ 185{
191 this->output_samples[0] = sample_output_stereo; 186 this->output_version = 0;
192 this->output_samples[1] = dsp_sample_output_format_change; 187 this->output_samples = sample_output_stereo;
193} 188}
194 189
195/* Flush the dither history */ 190/* Flush the dither history */
@@ -199,6 +194,7 @@ void dsp_sample_output_flush(struct sample_io_data *this)
199 memset(dither_data.state, 0, sizeof (dither_data.state)); 194 memset(dither_data.state, 0, sizeof (dither_data.state));
200} 195}
201 196
197
202/** Output settings **/ 198/** Output settings **/
203 199
204/* Set the tri-pdf dithered output */ 200/* Set the tri-pdf dithered output */
@@ -207,8 +203,11 @@ void dsp_dither_enable(bool enable)
207 if (enable == dither_data.enabled) 203 if (enable == dither_data.enabled)
208 return; 204 return;
209 205
210 struct sample_io_data *data = (void *)dsp_get_config(CODEC_IDX_AUDIO);
211 dsp_sample_output_flush(data);
212 dither_data.enabled = enable; 206 dither_data.enabled = enable;
213 data->output_samples[0] = dsp_sample_output_format_change; 207 struct sample_io_data *data = (void *)dsp_get_config(CODEC_IDX_AUDIO);
208
209 if (enable)
210 dsp_sample_output_flush(data);
211
212 data->output_version = 0; /* Force format update */
214} 213}
diff --git a/lib/rbcodec/dsp/eq.c b/lib/rbcodec/dsp/eq.c
index d58f0959b2..372ef9bbad 100644
--- a/lib/rbcodec/dsp/eq.c
+++ b/lib/rbcodec/dsp/eq.c
@@ -156,8 +156,10 @@ static intptr_t eq_configure(struct dsp_proc_entry *this,
156 { 156 {
157 case DSP_PROC_INIT: 157 case DSP_PROC_INIT:
158 if (value != 0) 158 if (value != 0)
159 break; 159 break; /* Already enabled */
160 this->process[0] = eq_process; 160
161 this->process = eq_process;
162 /* Fall-through */
161 case DSP_PROC_CLOSE: 163 case DSP_PROC_CLOSE:
162 pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT); 164 pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT);
163 break; 165 break;
@@ -167,7 +169,7 @@ static intptr_t eq_configure(struct dsp_proc_entry *this,
167 break; 169 break;
168 } 170 }
169 171
170 return 1; 172 return 0;
171 (void)dsp; 173 (void)dsp;
172} 174}
173 175
diff --git a/lib/rbcodec/dsp/lin_resample.c b/lib/rbcodec/dsp/lin_resample.c
index 34dc35b2dd..20bb78e68d 100644
--- a/lib/rbcodec/dsp/lin_resample.c
+++ b/lib/rbcodec/dsp/lin_resample.c
@@ -51,9 +51,8 @@ static struct resample_data
51 int32_t last_sample[2]; /* 08h: Last samples for interpolation (L+R) */ 51 int32_t last_sample[2]; /* 08h: Last samples for interpolation (L+R) */
52 /* 10h */ 52 /* 10h */
53 int32_t frequency; /* Virtual samplerate */ 53 int32_t frequency; /* Virtual samplerate */
54 struct dsp_config *dsp; /* The DSP for this resampler */
55 struct dsp_buffer resample_buf; /* Buffer descriptor for resampled data */ 54 struct dsp_buffer resample_buf; /* Buffer descriptor for resampled data */
56 int32_t *resample_buf_arr[2]; /* Actual output data pointers */ 55 int32_t *resample_out_p[2]; /* Actual output buffer pointers */
57} resample_data[DSP_COUNT] IBSS_ATTR; 56} resample_data[DSP_COUNT] IBSS_ATTR;
58 57
59/* Actual worker function. Implemented here or in target assembly code. */ 58/* Actual worker function. Implemented here or in target assembly code. */
@@ -75,9 +74,9 @@ static void lin_resample_flush(struct dsp_proc_entry *this)
75} 74}
76 75
77static bool lin_resample_new_delta(struct resample_data *data, 76static bool lin_resample_new_delta(struct resample_data *data,
78 struct dsp_buffer *buf) 77 struct sample_format *format)
79{ 78{
80 int32_t frequency = buf->format.frequency; /* virtual samplerate */ 79 int32_t frequency = format->frequency; /* virtual samplerate */
81 80
82 data->frequency = frequency; 81 data->frequency = frequency;
83 data->delta = fp_div(frequency, NATIVE_FREQUENCY, 16); 82 data->delta = fp_div(frequency, NATIVE_FREQUENCY, 16);
@@ -169,8 +168,8 @@ static void lin_resample_process(struct dsp_proc_entry *this,
169 return; /* data still remains */ 168 return; /* data still remains */
170 169
171 dst->remcount = 0; 170 dst->remcount = 0;
172 dst->p32[0] = data->resample_buf_arr[0]; 171 dst->p32[0] = data->resample_out_p[0];
173 dst->p32[1] = data->resample_buf_arr[1]; 172 dst->p32[1] = data->resample_out_p[1];
174 173
175 if (src->remcount > 0) 174 if (src->remcount > 0)
176 { 175 {
@@ -189,63 +188,44 @@ static void lin_resample_process(struct dsp_proc_entry *this,
189} 188}
190 189
191/* Finish draining old samples then switch format or shut off */ 190/* Finish draining old samples then switch format or shut off */
192static void lin_resample_new_format(struct dsp_proc_entry *this, 191static intptr_t lin_resample_new_format(struct dsp_proc_entry *this,
193 struct dsp_buffer **buf_p) 192 struct dsp_config *dsp,
193 struct sample_format *format)
194{ 194{
195 struct resample_data *data = (void *)this->data; 195 struct resample_data *data = (void *)this->data;
196 struct dsp_buffer *src = *buf_p;
197 struct dsp_buffer *dst = &data->resample_buf; 196 struct dsp_buffer *dst = &data->resample_buf;
198 197
199 if (dst->remcount > 0) 198 if (dst->remcount > 0)
200 { 199 return PROC_NEW_FORMAT_TRANSITION;
201 *buf_p = dst;
202 return; /* data still remains */
203 }
204 200
205 DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, DSP_PROC_RESAMPLE, src->format); 201 DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, *format);
206 202
207 struct dsp_config *dsp = data->dsp;
208 int32_t frequency = data->frequency; 203 int32_t frequency = data->frequency;
209 bool active = dsp_proc_active(dsp, DSP_PROC_RESAMPLE); 204 bool active = dsp_proc_active(dsp, DSP_PROC_RESAMPLE);
210 205
211 if (src->format.frequency != frequency) 206 if (format->frequency != frequency)
212 { 207 {
213 DEBUGF(" DSP_PROC_RESAMPLE- new delta\n"); 208 DEBUGF(" DSP_PROC_RESAMPLE- new delta\n");
214 active = lin_resample_new_delta(data, src); 209 active = lin_resample_new_delta(data, format);
215 dsp_proc_activate(dsp, DSP_PROC_RESAMPLE, active); 210 dsp_proc_activate(dsp, DSP_PROC_RESAMPLE, active);
216 } 211 }
217 212
218 /* Everything after us is NATIVE_FREQUENCY */ 213 /* Everything after us is NATIVE_FREQUENCY */
219 struct sample_format f = src->format; 214 dst->format = *format;
220 f.frequency = NATIVE_FREQUENCY; 215 dst->format.frequency = NATIVE_FREQUENCY;
221 f.codec_frequency = NATIVE_FREQUENCY; 216 dst->format.codec_frequency = NATIVE_FREQUENCY;
222
223 if (!active)
224 {
225 DEBUGF(" DSP_PROC_RESAMPLE- not active\n");
226 dst->format = f; /* Keep track */
227 return; /* No resampling required */
228 }
229
230 format_change_ack(&src->format);
231 217
232 if (EQU_SAMPLE_FORMAT(f, dst->format)) 218 if (active)
233 { 219 return PROC_NEW_FORMAT_OK;
234 DEBUGF(" DSP_PROC_RESAMPLE- same dst format\n");
235 format_change_ack(&f); /* Nothing changed that matters downstream */
236 }
237 220
238 dst->format = f; 221 /* No longer needed */
239 dsp_proc_call(this, buf_p, 0); 222 DEBUGF(" DSP_PROC_RESAMPLE- deactivated\n");
223 return PROC_NEW_FORMAT_DEACTIVATED;
240} 224}
241 225
242static void lin_resample_init(struct dsp_config *dsp, 226static void INIT_ATTR lin_resample_dsp_init(struct dsp_config *dsp,
243 enum dsp_ids dsp_id) 227 enum dsp_ids dsp_id)
244{ 228{
245 /* Always enable resampler so that format changes may be monitored and
246 * it self-activated when required */
247 dsp_proc_enable(dsp, DSP_PROC_RESAMPLE, true);
248
249 int32_t *lbuf, *rbuf; 229 int32_t *lbuf, *rbuf;
250 230
251 switch (dsp_id) 231 switch (dsp_id)
@@ -265,8 +245,19 @@ static void lin_resample_init(struct dsp_config *dsp,
265 return; 245 return;
266 } 246 }
267 247
268 resample_data[dsp_id].resample_buf_arr[0] = lbuf; 248 /* Always enable resampler so that format changes may be monitored and
269 resample_data[dsp_id].resample_buf_arr[1] = rbuf; 249 * it self-activated when required */
250 dsp_proc_enable(dsp, DSP_PROC_RESAMPLE, true);
251 resample_data[dsp_id].resample_out_p[0] = lbuf;
252 resample_data[dsp_id].resample_out_p[1] = rbuf;
253}
254
255static void INIT_ATTR lin_resample_proc_init(struct dsp_proc_entry *this,
256 struct dsp_config *dsp)
257{
258 dsp_proc_set_in_place(dsp, DSP_PROC_RESAMPLE, false);
259 this->data = (intptr_t)&resample_data[dsp_get_id(dsp)];
260 this->process = lin_resample_process;
270} 261}
271 262
272/* DSP message hook */ 263/* DSP message hook */
@@ -275,10 +266,12 @@ static intptr_t lin_resample_configure(struct dsp_proc_entry *this,
275 unsigned int setting, 266 unsigned int setting,
276 intptr_t value) 267 intptr_t value)
277{ 268{
269 intptr_t retval = 0;
270
278 switch (setting) 271 switch (setting)
279 { 272 {
280 case DSP_INIT: 273 case DSP_INIT:
281 lin_resample_init(dsp, (enum dsp_ids)value); 274 lin_resample_dsp_init(dsp, (enum dsp_ids)value);
282 break; 275 break;
283 276
284 case DSP_FLUSH: 277 case DSP_FLUSH:
@@ -286,21 +279,21 @@ static intptr_t lin_resample_configure(struct dsp_proc_entry *this,
286 break; 279 break;
287 280
288 case DSP_PROC_INIT: 281 case DSP_PROC_INIT:
289 this->data = (intptr_t)&resample_data[dsp_get_id(dsp)]; 282 lin_resample_proc_init(this, dsp);
290 this->ip_mask = 0; /* Not in-place */
291 this->process[0] = lin_resample_process;
292 this->process[1] = lin_resample_new_format;
293 ((struct resample_data *)this->data)->dsp = dsp;
294 break; 283 break;
295 284
296 case DSP_PROC_CLOSE: 285 case DSP_PROC_CLOSE:
297 /* This stage should be enabled at all times */ 286 /* This stage should be enabled at all times */
298 DEBUGF("DSP_PROC_RESAMPLE- Error: Closing!\n"); 287 DEBUGF("DSP_PROC_RESAMPLE- Error: Closing!\n");
299 break; 288 break;
289
290 case DSP_PROC_NEW_FORMAT:
291 retval = lin_resample_new_format(this, dsp,
292 (struct sample_format *)value);
293 break;
300 } 294 }
301 295
302 return 1; 296 return retval;
303 (void)value;
304} 297}
305 298
306/* Database entry */ 299/* Database entry */
diff --git a/lib/rbcodec/dsp/pga.c b/lib/rbcodec/dsp/pga.c
index de852d01d4..522789fcf2 100644
--- a/lib/rbcodec/dsp/pga.c
+++ b/lib/rbcodec/dsp/pga.c
@@ -129,13 +129,14 @@ static intptr_t pga_configure(struct dsp_proc_entry *this,
129 { 129 {
130 case DSP_PROC_INIT: 130 case DSP_PROC_INIT:
131 if (value != 0) 131 if (value != 0)
132 break; /* Already initialized */ 132 break; /* Already enabled */
133
133 this->data = (intptr_t)&pga_data; 134 this->data = (intptr_t)&pga_data;
134 this->process[0] = pga_process; 135 this->process = pga_process;
135 break; 136 break;
136 } 137 }
137 138
138 return 1; 139 return 0;
139 (void)dsp; 140 (void)dsp;
140} 141}
141 142
diff --git a/lib/rbcodec/dsp/tdspeed.c b/lib/rbcodec/dsp/tdspeed.c
index 6a495bd989..e668c85032 100644
--- a/lib/rbcodec/dsp/tdspeed.c
+++ b/lib/rbcodec/dsp/tdspeed.c
@@ -53,7 +53,6 @@ enum tdspeed_ops
53static struct tdspeed_state_s 53static struct tdspeed_state_s
54{ 54{
55 struct dsp_proc_entry *this; /* this stage */ 55 struct dsp_proc_entry *this; /* this stage */
56 struct dsp_config *dsp; /* the DSP we use */
57 int channels; /* number of audio channels */ 56 int channels; /* number of audio channels */
58 int32_t samplerate; /* current samplerate of input data */ 57 int32_t samplerate; /* current samplerate of input data */
59 int32_t factor; /* stretch factor (perdecimille) */ 58 int32_t factor; /* stretch factor (perdecimille) */
@@ -131,6 +130,10 @@ static bool tdspeed_update(int32_t samplerate, int32_t factor)
131 st->samplerate = samplerate; 130 st->samplerate = samplerate;
132 st->factor = factor; 131 st->factor = factor;
133 132
133 /* just discard remaining input data */
134 st->ovl_size = 0;
135 st->ovl_shift = 0;
136
134 /* Check parameters */ 137 /* Check parameters */
135 if (factor == PITCH_SPEED_100) 138 if (factor == PITCH_SPEED_100)
136 return false; 139 return false;
@@ -161,10 +164,6 @@ static bool tdspeed_update(int32_t samplerate, int32_t factor)
161 st->shift_max = (st->dst_step > st->src_step) ? 164 st->shift_max = (st->dst_step > st->src_step) ?
162 st->dst_step : st->src_step; 165 st->dst_step : st->src_step;
163 166
164 /* just discard remaining input data */
165 st->ovl_size = 0;
166 st->ovl_shift = 0;
167
168 st->ovl_buff[0] = overlap_buffer[0]; 167 st->ovl_buff[0] = overlap_buffer[0];
169 st->ovl_buff[1] = overlap_buffer[1]; /* ignored if mono */ 168 st->ovl_buff[1] = overlap_buffer[1]; /* ignored if mono */
170 169
@@ -378,17 +377,14 @@ skip:;
378 377
379/** DSP interface **/ 378/** DSP interface **/
380 379
381static void tdspeed_process_new_format(struct dsp_proc_entry *this,
382 struct dsp_buffer **buf_p);
383
384/* Enable or disable the availability of timestretch */ 380/* Enable or disable the availability of timestretch */
385void dsp_timestretch_enable(bool enabled) 381void dsp_timestretch_enable(bool enabled)
386{ 382{
387 if (enabled != !tdspeed_state.this) 383 if (enabled != !tdspeed_state.this)
388 return; /* No change */ 384 return; /* No change */
389 385
390 dsp_proc_enable(dsp_get_config(CODEC_IDX_AUDIO), DSP_PROC_TIMESTRETCH, 386 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
391 enabled); 387 dsp_proc_enable(dsp, DSP_PROC_TIMESTRETCH, enabled);
392} 388}
393 389
394/* Set the timestretch ratio */ 390/* Set the timestretch ratio */
@@ -405,7 +401,8 @@ void dsp_set_timestretch(int32_t percent)
405 if (percent == st->factor) 401 if (percent == st->factor)
406 return; /* no change */ 402 return; /* no change */
407 403
408 dsp_configure(st->dsp, TIMESTRETCH_SET_FACTOR, percent); 404 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
405 dsp_configure(dsp, TIMESTRETCH_SET_FACTOR, percent);
409} 406}
410 407
411/* Return the timestretch ratio */ 408/* Return the timestretch ratio */
@@ -459,27 +456,22 @@ static void tdspeed_process(struct dsp_proc_entry *this,
459} 456}
460 457
461/* Process format changes and settings changes */ 458/* Process format changes and settings changes */
462static void tdspeed_process_new_format(struct dsp_proc_entry *this, 459static intptr_t tdspeed_new_format(struct dsp_proc_entry *this,
463 struct dsp_buffer **buf_p) 460 struct dsp_config *dsp,
461 struct sample_format *format)
464{ 462{
465 struct dsp_buffer *src = *buf_p;
466 struct dsp_buffer *dst = &dsp_outbuf; 463 struct dsp_buffer *dst = &dsp_outbuf;
467 464
468 if (dst->remcount > 0) 465 if (dst->remcount > 0)
469 { 466 return PROC_NEW_FORMAT_TRANSITION;
470 *buf_p = dst;
471 return; /* output remains from an earlier call */
472 }
473 467
474 DSP_PRINT_FORMAT(DSP_PROC_TIMESTRETCH, DSP_PROC_TIMESTRETCH, src->format); 468 DSP_PRINT_FORMAT(DSP_PROC_TIMESTRETCH, *format);
475 469
470 bool active = dsp_proc_active(dsp, DSP_PROC_TIMESTRETCH);
476 struct tdspeed_state_s *st = &tdspeed_state; 471 struct tdspeed_state_s *st = &tdspeed_state;
477 struct dsp_config *dsp = st->dsp;
478 struct sample_format *format = &src->format;
479 int channels = format->num_channels; 472 int channels = format->num_channels;
480 473
481 if (format->codec_frequency != st->samplerate || 474 if (format->codec_frequency != st->samplerate)
482 !dsp_proc_active(dsp, DSP_PROC_TIMESTRETCH))
483 { 475 {
484 /* relevent parameters are changing - all overlap will be discarded */ 476 /* relevent parameters are changing - all overlap will be discarded */
485 st->channels = channels; 477 st->channels = channels;
@@ -489,17 +481,10 @@ static void tdspeed_process_new_format(struct dsp_proc_entry *this,
489 channels, 481 channels,
490 format->codec_frequency, 482 format->codec_frequency,
491 st->factor / 100, st->factor % 100); 483 st->factor / 100, st->factor % 100);
492 bool active = tdspeed_update(format->codec_frequency, st->factor); 484 active = tdspeed_update(format->codec_frequency, st->factor);
493 dsp_proc_activate(dsp, DSP_PROC_TIMESTRETCH, active); 485 dsp_proc_activate(dsp, DSP_PROC_TIMESTRETCH, active);
494
495 if (!active)
496 {
497 DEBUGF(" DSP_PROC_RESAMPLE- not active\n");
498 dst->format = src->format; /* Keep track */
499 return; /* no more for now */
500 }
501 } 486 }
502 else if (channels != st->channels) 487 else if (active && channels != st->channels)
503 { 488 {
504 /* channel count transistion - have to make old data in overlap 489 /* channel count transistion - have to make old data in overlap
505 buffer compatible with new format */ 490 buffer compatible with new format */
@@ -525,20 +510,25 @@ static void tdspeed_process_new_format(struct dsp_proc_entry *this,
525 } 510 }
526 } 511 }
527 512
528 struct sample_format f = *format; 513 dst->format = *format;
529 format_change_ack(format);
530 514
531 if (EQU_SAMPLE_FORMAT(f, dst->format)) 515 if (active)
532 { 516 return PROC_NEW_FORMAT_OK;
533 DEBUGF(" DSP_PROC_TIMESTRETCH- same dst format\n");
534 format_change_ack(&f); /* nothing changed that matters downstream */
535 }
536 517
537 dst->format = f; 518 /* Nothing to do */
519 DEBUGF(" DSP_PROC_RESAMPLE- deactivated\n");
520 return PROC_NEW_FORMAT_DEACTIVATED;
538 521
539 /* return to normal processing */ 522 (void)this;
540 this->process[0] = tdspeed_process; 523}
541 dsp_proc_call(this, buf_p, 0); 524
525static void INIT_ATTR tdspeed_dsp_init(struct tdspeed_state_s *st,
526 enum dsp_ids dsp_id)
527{
528 /* everything is at 100% until dsp_set_timestretch is called with
529 some other value and timestretch is enabled at the time */
530 if (dsp_id == CODEC_IDX_AUDIO)
531 st->factor = PITCH_SPEED_100;
542} 532}
543 533
544/* DSP message hook */ 534/* DSP message hook */
@@ -547,15 +537,14 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
547 unsigned int setting, 537 unsigned int setting,
548 intptr_t value) 538 intptr_t value)
549{ 539{
540 intptr_t retval = 0;
541
550 struct tdspeed_state_s *st = &tdspeed_state; 542 struct tdspeed_state_s *st = &tdspeed_state;
551 543
552 switch (setting) 544 switch (setting)
553 { 545 {
554 case DSP_INIT: 546 case DSP_INIT:
555 /* everything is at 100% until dsp_set_timestretch is called with 547 tdspeed_dsp_init(st, (enum dsp_ids)value);
556 some other value and timestretch is enabled at the time */
557 if (value == CODEC_IDX_AUDIO)
558 st->factor = PITCH_SPEED_100;
559 break; 548 break;
560 549
561 case DSP_FLUSH: 550 case DSP_FLUSH:
@@ -567,10 +556,8 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
567 return -1; /* fail the init */ 556 return -1; /* fail the init */
568 557
569 st->this = this; 558 st->this = this;
570 st->dsp = dsp; 559 dsp_proc_set_in_place(dsp, DSP_PROC_TIMESTRETCH, false);
571 this->ip_mask = 0; /* not in-place */ 560 this->process = tdspeed_process;
572 this->process[0] = tdspeed_process;
573 this->process[1] = tdspeed_process_new_format;
574 break; 561 break;
575 562
576 case DSP_PROC_CLOSE: 563 case DSP_PROC_CLOSE:
@@ -580,17 +567,18 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
580 tdspeed_free_buffers(buffers, NBUFFERS); 567 tdspeed_free_buffers(buffers, NBUFFERS);
581 break; 568 break;
582 569
570 case DSP_PROC_NEW_FORMAT:
571 retval = tdspeed_new_format(this, dsp, (struct sample_format *)value);
572 break;
573
583 case TIMESTRETCH_SET_FACTOR: 574 case TIMESTRETCH_SET_FACTOR:
584 /* force update as a format change */
585 st->samplerate = 0; 575 st->samplerate = 0;
586 st->factor = (int32_t)value; 576 st->factor = (int32_t)value;
587 st->this->process[0] = tdspeed_process_new_format; 577 dsp_proc_want_format_update(dsp, DSP_PROC_TIMESTRETCH);
588 dsp_proc_activate(st->dsp, DSP_PROC_TIMESTRETCH, true);
589 break; 578 break;
590 } 579 }
591 580
592 return 1; 581 return retval;
593 (void)value;
594} 582}
595 583
596void tdspeed_move(int i, void* current, void* new) 584void tdspeed_move(int i, void* current, void* new)
diff --git a/lib/rbcodec/dsp/tone_controls.c b/lib/rbcodec/dsp/tone_controls.c
index 922c966e3f..01381ea330 100644
--- a/lib/rbcodec/dsp/tone_controls.c
+++ b/lib/rbcodec/dsp/tone_controls.c
@@ -90,7 +90,7 @@ static void tone_process(struct dsp_proc_entry *this,
90 struct dsp_buffer **buf_p) 90 struct dsp_buffer **buf_p)
91{ 91{
92 struct dsp_buffer *buf = *buf_p; 92 struct dsp_buffer *buf = *buf_p;
93 filter_process((void *)this->data, buf->p32, buf->remcount, 93 filter_process((struct dsp_filter *)this->data, buf->p32, buf->remcount,
94 buf->format.num_channels); 94 buf->format.num_channels);
95} 95}
96 96
@@ -104,15 +104,17 @@ static intptr_t tone_configure(struct dsp_proc_entry *this,
104 { 104 {
105 case DSP_PROC_INIT: 105 case DSP_PROC_INIT:
106 if (value != 0) 106 if (value != 0)
107 break; 107 break; /* Already enabled */
108
108 this->data = (intptr_t)&tone_filters[dsp_get_id(dsp)]; 109 this->data = (intptr_t)&tone_filters[dsp_get_id(dsp)];
109 this->process[0] = tone_process; 110 this->process = tone_process;
111 /* Fall-through */
110 case DSP_FLUSH: 112 case DSP_FLUSH:
111 filter_flush((struct dsp_filter *)this->data); 113 filter_flush((struct dsp_filter *)this->data);
112 break; 114 break;
113 } 115 }
114 116
115 return 1; 117 return 0;
116} 118}
117 119
118/* Database entry */ 120/* Database entry */