summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 */