diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2012-12-19 17:34:57 -0500 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2013-05-04 13:43:33 -0400 |
commit | 78a45b47dede5ddf35dfc53e965b486a79177b18 (patch) | |
tree | edb3ad7c101e600a7cc3be4b40380430cbeb3e55 /lib/rbcodec | |
parent | cdb71c707bb434f44368b72f2db3becc37b7a46c (diff) | |
download | rockbox-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
Diffstat (limited to 'lib/rbcodec')
-rw-r--r-- | lib/rbcodec/dsp/channel_mode.c | 98 | ||||
-rw-r--r-- | lib/rbcodec/dsp/compressor.c | 6 | ||||
-rw-r--r-- | lib/rbcodec/dsp/crossfeed.c | 122 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_core.c | 342 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_core.h | 37 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_misc.c | 35 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_proc_entry.h | 43 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_sample_input.c | 92 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_sample_io.h | 23 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_sample_output.c | 33 | ||||
-rw-r--r-- | lib/rbcodec/dsp/eq.c | 8 | ||||
-rw-r--r-- | lib/rbcodec/dsp/lin_resample.c | 97 | ||||
-rw-r--r-- | lib/rbcodec/dsp/pga.c | 7 | ||||
-rw-r--r-- | lib/rbcodec/dsp/tdspeed.c | 100 | ||||
-rw-r--r-- | lib/rbcodec/dsp/tone_controls.c | 10 |
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 | ||
71 | static 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. */ | ||
172 | static 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 | |||
196 | void channel_mode_set_config(int value) | 153 | void 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 | ||
188 | static 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 */ | ||
204 | static 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 */ |
232 | static intptr_t channel_mode_configure(struct dsp_proc_entry *this, | 224 | static 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 | ||
75 | static int crossfeed_type = CROSSFEED_TYPE_NONE; | 74 | static 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 */ | ||
98 | static 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 */ |
139 | void dsp_set_crossfeed_type(int type) | 97 | void 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 */ | ||
235 | static 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 */ | ||
260 | static 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 */ |
277 | static intptr_t crossfeed_configure(struct dsp_proc_entry *this, | 284 | static 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 @@ | |||
41 | struct dsp_config | 48 | struct 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. */ |
63 | static struct dsp_proc_slot | 69 | static struct dsp_proc_slot |
64 | dsp_proc_slot_arr[DSP_NUM_PROC_STAGES+DSP_VOICE_NUM_PROC_STAGES] IBSS_ATTR; | 70 | dsp_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; | |||
67 | static struct dsp_config dsp_conf[DSP_COUNT] IBSS_ATTR; | 73 | static struct dsp_config dsp_conf[DSP_COUNT] IBSS_ATTR; |
68 | 74 | ||
69 | /** Processing stages support functions **/ | 75 | /** Processing stages support functions **/ |
76 | static const struct dsp_proc_db_entry * | ||
77 | proc_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 */ |
72 | static struct dsp_proc_slot * find_proc_slot(struct dsp_config *dsp, | 83 | static 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] */ | ||
114 | static 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] */ | ||
121 | static 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 */ |
146 | static struct dsp_proc_slot * | 126 | static struct dsp_proc_slot * |
147 | dsp_proc_enable_enlink(struct dsp_config *dsp, uint32_t mask) | 127 | dsp_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) | |||
203 | static struct dsp_proc_slot * | 181 | static struct dsp_proc_slot * |
204 | dsp_proc_enable_delink(struct dsp_config *dsp, uint32_t mask) | 182 | dsp_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 | ||
228 | void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, | 206 | void 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. */ | ||
278 | static struct dsp_proc_slot * | ||
279 | dsp_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? */ |
322 | bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id) | 276 | bool 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 |
328 | static FORCE_INLINE bool dsp_proc_should_call(struct dsp_proc_entry *this, | 282 | * buffer is sent to process() */ |
329 | struct dsp_buffer *buf, | 283 | void 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 */ |
341 | bool dsp_proc_call(struct dsp_proc_entry *this, struct dsp_buffer **buf_p, | 293 | void 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 */ | ||
310 | static 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 | 336 | static 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 */ | ||
499 | bool 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. */ |
507 | void INIT_ATTR dsp_init(void) | 485 | void 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 */ |
58 | struct sample_format | 60 | struct 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 | |||
74 | static inline void format_change_set(struct sample_format *f) | ||
75 | { f->changed = 1; } | ||
76 | static 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 */ |
80 | struct dsp_buffer | 75 | struct 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 */ |
150 | struct dsp_config * dsp_get_config(enum dsp_ids id); | 132 | struct dsp_config * dsp_get_config(enum dsp_ids id); |
151 | 133 | ||
152 | /* Get DSP id */ | 134 | /* Get DSP id */ |
153 | enum dsp_ids dsp_get_id(const struct dsp_config *dsp); | 135 | enum 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? */ | ||
157 | bool 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 | ||
114 | static void dsp_pitch_update(struct dsp_config *dsp) | 113 | static 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 | ||
124 | static void dsp_set_pitch(int32_t percent) | 119 | static 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 | ||
176 | static 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 | */ |
113 | struct dsp_proc_entry | 111 | struct 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 */ | ||
118 | enum | ||
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? */ |
138 | bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id); | 143 | bool 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() */ |
142 | bool dsp_proc_call(struct dsp_proc_entry *this, struct dsp_buffer **buf_p, | 147 | void 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 */ | ||
151 | void 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 | ||
145 | struct dsp_proc_db_entry | 164 | struct 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 | ||
51 | extern void dsp_sample_output_init(struct sample_io_data *this); | 51 | extern void dsp_sample_output_init(struct sample_io_data *this); |
52 | extern void dsp_sample_output_flush(struct sample_io_data *this); | 52 | extern void dsp_sample_output_flush(struct sample_io_data *this); |
53 | extern 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 */ |
214 | static void dsp_sample_input_format_change(struct sample_io_data *this, | 216 | void 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; | 244 | static 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); | 254 | static void dsp_sample_input_flush(struct sample_io_data *this) |
255 | { | ||
256 | this->sample_buf.remcount = 0; | ||
253 | } | 257 | } |
254 | 258 | ||
255 | static void dsp_sample_input_init(struct sample_io_data *this, | 259 | static 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 */ | 285 | static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this, |
285 | static 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 | ||
290 | void dsp_sample_io_configure(struct sample_io_data *this, | 292 | void 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 */ |
43 | struct sample_io_data | 43 | struct 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 | ||
58 | void dsp_sample_input_format_change(struct sample_io_data *this, | ||
59 | struct sample_format *format); | ||
60 | |||
61 | void 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 */ |
56 | void dsp_sample_io_configure(struct sample_io_data *this, | 65 | void 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 */ |
162 | static void dsp_sample_output_format_change(struct sample_io_data *this, | 163 | void 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 | ||
189 | void dsp_sample_output_init(struct sample_io_data *this) | 184 | void 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 | ||
77 | static bool lin_resample_new_delta(struct resample_data *data, | 76 | static 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 */ |
192 | static void lin_resample_new_format(struct dsp_proc_entry *this, | 191 | static 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 | ||
242 | static void lin_resample_init(struct dsp_config *dsp, | 226 | static 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 | |||
255 | static 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 | |||
53 | static struct tdspeed_state_s | 53 | static 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 | ||
381 | static 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 */ |
385 | void dsp_timestretch_enable(bool enabled) | 381 | void 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 */ |
462 | static void tdspeed_process_new_format(struct dsp_proc_entry *this, | 459 | static 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 | |
525 | static 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 | ||
596 | void tdspeed_move(int i, void* current, void* new) | 584 | void 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 */ |