summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2012-12-19 17:34:57 -0500
committerMichael Sevakis <jethead71@rockbox.org>2013-05-04 13:43:33 -0400
commit78a45b47dede5ddf35dfc53e965b486a79177b18 (patch)
treeedb3ad7c101e600a7cc3be4b40380430cbeb3e55
parentcdb71c707bb434f44368b72f2db3becc37b7a46c (diff)
downloadrockbox-78a45b4.tar.gz
rockbox-78a45b4.zip
Cleanup and simplify latest DSP code incarnation.
Some things can just be a bit simpler in handling the list of stages and some things, especially format change handling, can be simplified for each stage implementation. Format changes are sent through the configure() callback. Hide some internal details and variables from processing stages and let the core deal with it. Do some miscellaneous cleanup and keep things a bit better factored. Change-Id: I19dd8ce1d0b792ba914d426013088a49a52ecb7e
-rw-r--r--lib/rbcodec/dsp/channel_mode.c98
-rw-r--r--lib/rbcodec/dsp/compressor.c6
-rw-r--r--lib/rbcodec/dsp/crossfeed.c122
-rw-r--r--lib/rbcodec/dsp/dsp_core.c342
-rw-r--r--lib/rbcodec/dsp/dsp_core.h37
-rw-r--r--lib/rbcodec/dsp/dsp_misc.c35
-rw-r--r--lib/rbcodec/dsp/dsp_proc_entry.h43
-rw-r--r--lib/rbcodec/dsp/dsp_sample_input.c92
-rw-r--r--lib/rbcodec/dsp/dsp_sample_io.h23
-rw-r--r--lib/rbcodec/dsp/dsp_sample_output.c33
-rw-r--r--lib/rbcodec/dsp/eq.c8
-rw-r--r--lib/rbcodec/dsp/lin_resample.c97
-rw-r--r--lib/rbcodec/dsp/pga.c7
-rw-r--r--lib/rbcodec/dsp/tdspeed.c100
-rw-r--r--lib/rbcodec/dsp/tone_controls.c10
15 files changed, 513 insertions, 540 deletions
diff --git a/lib/rbcodec/dsp/channel_mode.c b/lib/rbcodec/dsp/channel_mode.c
index 78e7b8f10c..2ae2d45fd3 100644
--- a/lib/rbcodec/dsp/channel_mode.c
+++ b/lib/rbcodec/dsp/channel_mode.c
@@ -49,30 +49,14 @@ static struct channel_mode_data
{
long sw_gain; /* 00h: for mode: custom */
long sw_cross; /* 04h: for mode: custom */
- struct dsp_config *dsp;
int mode;
- const dsp_proc_fn_type fns[SOUND_CHAN_NUM_MODES];
} channel_mode_data =
{
.sw_gain = 0,
.sw_cross = 0,
- .mode = SOUND_CHAN_STEREO,
- .fns =
- {
- [SOUND_CHAN_STEREO] = NULL,
- [SOUND_CHAN_MONO] = channel_mode_proc_mono,
- [SOUND_CHAN_CUSTOM] = channel_mode_proc_custom,
- [SOUND_CHAN_MONO_LEFT] = channel_mode_proc_mono_left,
- [SOUND_CHAN_MONO_RIGHT] = channel_mode_proc_mono_right,
- [SOUND_CHAN_KARAOKE] = channel_mode_proc_karaoke,
- },
+ .mode = SOUND_CHAN_STEREO
};
-static dsp_proc_fn_type get_process_fn(void)
-{
- return channel_mode_data.fns[channel_mode_data.mode];
-}
-
#if 0
/* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for
* completeness. */
@@ -166,33 +150,6 @@ void channel_mode_proc_mono_right(struct dsp_proc_entry *this,
(void)this;
}
-/* This is the initial function pointer when first enabled/changed in order
- * to facilitate verification of the format compatibility at the proper time
- * This gets called for changes even if stage is inactive. */
-static void channel_mode_process_new_format(struct dsp_proc_entry *this,
- struct dsp_buffer **buf_p)
-{
- struct channel_mode_data *data = (void *)this->data;
- struct dsp_buffer *buf = *buf_p;
-
- DSP_PRINT_FORMAT(DSP_PROC_CHANNEL_MODE, DSP_PROC_CHANNEL_MODE,
- buf->format);
-
- bool active = buf->format.num_channels >= 2;
- dsp_proc_activate(data->dsp, DSP_PROC_CHANNEL_MODE, active);
-
- if (!active)
- {
- /* Can't do this. Sleep until next change. */
- DEBUGF(" DSP_PROC_CHANNEL_MODE- deactivated\n");
- return;
- }
-
- /* Switch to the real function and call it once */
- this->process[0] = get_process_fn();
- dsp_proc_call(this, buf_p, (unsigned)buf->format.changed - 1);
-}
-
void channel_mode_set_config(int value)
{
if (value < 0 || value >= SOUND_CHAN_NUM_MODES)
@@ -228,34 +185,65 @@ void channel_mode_custom_set_width(int value)
channel_mode_data.sw_cross = cross << 8;
}
+static void update_process_fn(struct dsp_proc_entry *this)
+{
+ static const dsp_proc_fn_type fns[SOUND_CHAN_NUM_MODES] =
+ {
+ [SOUND_CHAN_STEREO] = NULL,
+ [SOUND_CHAN_MONO] = channel_mode_proc_mono,
+ [SOUND_CHAN_CUSTOM] = channel_mode_proc_custom,
+ [SOUND_CHAN_MONO_LEFT] = channel_mode_proc_mono_left,
+ [SOUND_CHAN_MONO_RIGHT] = channel_mode_proc_mono_right,
+ [SOUND_CHAN_KARAOKE] = channel_mode_proc_karaoke,
+ };
+
+ this->process = fns[((struct channel_mode_data *)this->data)->mode];
+}
+
+/* Handle format changes and verify the format compatibility */
+static intptr_t channel_mode_new_format(struct dsp_proc_entry *this,
+ struct dsp_config *dsp,
+ struct sample_format *format)
+{
+ DSP_PRINT_FORMAT(DSP_PROC_CHANNEL_MODE, format);
+
+ bool active = format->num_channels >= 2;
+ dsp_proc_activate(dsp, DSP_PROC_CHANNEL_MODE, active);
+
+ if (active)
+ return PROC_NEW_FORMAT_OK;
+
+ /* Can't do this. Sleep until next change. */
+ DEBUGF(" DSP_PROC_CHANNEL_MODE- deactivated\n");
+ return PROC_NEW_FORMAT_DEACTIVATED;
+
+ (void)this;
+}
+
/* DSP message hook */
static intptr_t channel_mode_configure(struct dsp_proc_entry *this,
struct dsp_config *dsp,
unsigned int setting,
intptr_t value)
{
+ intptr_t retval = 0;
+
switch (setting)
{
case DSP_PROC_INIT:
if (value == 0)
- {
- /* New object */
this->data = (intptr_t)&channel_mode_data;
- this->process[1] = channel_mode_process_new_format;
- ((struct channel_mode_data *)this->data)->dsp = dsp;
- }
- /* Force format change call each time */
- this->process[0] = channel_mode_process_new_format;
- dsp_proc_activate(dsp, DSP_PROC_CHANNEL_MODE, true);
+ update_process_fn(this);
break;
- case DSP_PROC_CLOSE:
- ((struct channel_mode_data *)this->data)->dsp = NULL;
+ case DSP_PROC_NEW_FORMAT:
+ retval = channel_mode_new_format(this, dsp,
+ (struct sample_format *)value);
break;
}
- return 1;
+ return retval;
}
/* 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,
case DSP_PROC_INIT:
if (value != 0)
break; /* Already enabled */
- this->process[0] = compressor_process;
+
+ this->process = compressor_process;
+ /* Fall-through */
case DSP_RESET:
case DSP_FLUSH:
release_gain = UNITY;
break;
}
- return 1;
+ return 0;
(void)dsp;
}
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
};
};
int32_t *index; /* 88h: Current pointer into the delay line */
- struct dsp_config *dsp; /* 8ch: Current DSP */
- /* 90h */
+ /* 8ch */
} crossfeed_state IBSS_ATTR;
static int crossfeed_type = CROSSFEED_TYPE_NONE;
@@ -79,62 +78,21 @@ static void crossfeed_flush(struct dsp_proc_entry *this)
{
struct crossfeed_state *state = (void *)this->data;
- if (crossfeed_type == CROSSFEED_TYPE_CUSTOM)
+ if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
{
- memset(state->history, 0,
- sizeof (state->history) + sizeof (state->delay));
- state->index = state->delay;
+ state->vcl = state->vcr = state->vdiff = 0;
}
else
{
- state->vcl = state->vcr = state->vdiff = 0;
+ memset(state->history, 0,
+ sizeof (state->history) + sizeof (state->delay));
+ state->index = state->delay;
}
}
/** DSP interface **/
-/* Crossfeed boot/format change function */
-static void crossfeed_process_new_format(struct dsp_proc_entry *this,
- struct dsp_buffer **buf_p)
-{
- struct crossfeed_state *state = (void *)this->data;
- struct dsp_buffer *buf = *buf_p;
-
- DSP_PRINT_FORMAT(DSP_PROC_CROSSFEED, DSP_PROC_CROSSFEED, buf->format);
-
- bool was_active = dsp_proc_active(state->dsp, DSP_PROC_CROSSFEED);
- bool active = buf->format.num_channels >= 2;
- dsp_proc_activate(state->dsp, DSP_PROC_CROSSFEED, active);
-
- if (!active)
- {
- /* Can't do this. Sleep until next change */
- DEBUGF(" DSP_PROC_CROSSFEED- deactivated\n");
- return;
- }
-
- dsp_proc_fn_type fn = crossfeed_process;
-
- if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
- {
- /* 1 / (F.Rforward.C) */
- state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128;
- /* 1 / (F.Rcross.C) */
- state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000;
- fn = crossfeed_meier_process;
- }
-
- if (!was_active || this->process[0] != fn)
- {
- crossfeed_flush(this); /* Going online or actual type change */
- this->process[0] = fn; /* Set real function */
- }
-
- /* Call it once */
- dsp_proc_call(this, buf_p, (unsigned)buf->format.changed - 1);
-}
-
/* Set the type of crossfeed to use */
void dsp_set_crossfeed_type(int type)
{
@@ -273,39 +231,83 @@ void crossfeed_meier_process(struct dsp_proc_entry *this,
}
#endif /* CPU */
+/* Update the processing function according to crossfeed type */
+static void update_process_fn(struct dsp_proc_entry *this,
+ struct dsp_config *dsp)
+{
+ struct crossfeed_state *state = (struct crossfeed_state *)this->data;
+ dsp_proc_fn_type fn = crossfeed_process;
+
+ if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
+ {
+ /* Set up for Meier */
+ /* 1 / (F.Rforward.C) */
+ state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128;
+ /* 1 / (F.Rcross.C) */
+ state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000;
+ fn = crossfeed_meier_process;
+ }
+
+ if (this->process != fn)
+ {
+ this->process = fn; /* Set proper function */
+ if (dsp_proc_active(dsp, DSP_PROC_CROSSFEED))
+ crossfeed_flush(this);
+ }
+}
+
+/* Crossfeed boot/format change function */
+static intptr_t crossfeed_new_format(struct dsp_proc_entry *this,
+ struct dsp_config *dsp,
+ struct sample_format *format)
+{
+ DSP_PRINT_FORMAT(DSP_PROC_CROSSFEED, format);
+
+ bool was_active = dsp_proc_active(dsp, DSP_PROC_CROSSFEED);
+ bool active = format->num_channels >= 2;
+ dsp_proc_activate(dsp, DSP_PROC_CROSSFEED, active);
+
+ if (active)
+ {
+ if (!was_active)
+ crossfeed_flush(this); /* Going online */
+
+ return PROC_NEW_FORMAT_OK;
+ }
+
+ /* Can't do this. Sleep until next change */
+ DEBUGF(" DSP_PROC_CROSSFEED- deactivated\n");
+ return PROC_NEW_FORMAT_DEACTIVATED;
+}
+
/* DSP message hook */
static intptr_t crossfeed_configure(struct dsp_proc_entry *this,
struct dsp_config *dsp,
unsigned int setting,
intptr_t value)
{
+ intptr_t retval = 0;
+
switch (setting)
{
case DSP_PROC_INIT:
if (value == 0)
- {
- /* New object */
this->data = (intptr_t)&crossfeed_state;
- this->process[1] = crossfeed_process_new_format;
- ((struct crossfeed_state *)this->data)->dsp = dsp;
- }
- /* Force format change call each time */
- this->process[0] = crossfeed_process_new_format;
- dsp_proc_activate(dsp, DSP_PROC_CROSSFEED, true);
+ update_process_fn(this, dsp);
break;
case DSP_FLUSH:
crossfeed_flush(this);
break;
- case DSP_PROC_CLOSE:
- ((struct crossfeed_state *)this->data)->dsp = NULL;
+ case DSP_PROC_NEW_FORMAT:
+ retval = crossfeed_new_format(this, dsp,
+ (struct sample_format *)value);
break;
}
- return 1;
- (void)value;
+ return retval;
}
/* 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 @@
#define DSP_PROC_DB_CREATE
#include "dsp_proc_entry.h"
+#ifndef DSP_PROCESS_START
+/* These do nothing if not previously defined */
+#define DSP_PROCESS_START()
+#define DSP_PROCESS_LOOP()
+#define DSP_PROCESS_END()
+#endif /* !DSP_PROCESS_START */
+
/* Linked lists give fewer loads in processing loop compared to some index
* list, which is more important than keeping occasionally executed code
* simple */
@@ -41,24 +48,23 @@
struct dsp_config
{
/** General DSP-local data **/
- struct sample_io_data io_data; /* Sample input-output data (first) */
- uint32_t slot_free_mask; /* Mask of free slots for this DSP */
- uint32_t proc_masks[2]; /* Mask of active/enabled stages */
+ struct sample_io_data io_data; /* Sample input-output data (first) */
+ uint32_t slot_free_mask; /* Mask of free slots for this DSP */
+ uint32_t proc_mask_enabled; /* Mask of enabled stages */
+ uint32_t proc_mask_active; /* Mask of active stages */
struct dsp_proc_slot
{
struct dsp_proc_entry proc_entry; /* This enabled stage */
- struct dsp_proc_slot *next[2]; /* [0]=active next, [1]=enabled next */
- const struct dsp_proc_db_entry *db_entry;
- } *proc_slots[2]; /* Pointer to first in list of
- active/enabled stages */
-
- /** Misc. extra stuff **/
-#if 0 /* Not needed now but enable if something must know this */
- bool processing; /* DSP is processing (to thwart inopportune
- buffer moves) */
-#endif
+ struct dsp_proc_slot *next; /* Next enabled slot */
+ uint32_t mask; /* In place operation mask/flag */
+ uint8_t version; /* Sample format version */
+ uint8_t db_index; /* Index in database array */
+ } *proc_slots; /* Pointer to first in list of enabled
+ stages */
};
+#define NACT_BIT BIT_N(___DSP_PROC_ID_RESERVED)
+
/* Pool of slots for stages - supports 32 or fewer combined as-is atm. */
static struct dsp_proc_slot
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;
static struct dsp_config dsp_conf[DSP_COUNT] IBSS_ATTR;
/** Processing stages support functions **/
+static const struct dsp_proc_db_entry *
+proc_db_entry(const struct dsp_proc_slot *s)
+{
+ return dsp_proc_database[s->db_index];
+}
/* Find the slot for a given enabled id */
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,
{
const uint32_t mask = BIT_N(id);
- if ((dsp->proc_masks[1] & mask) == 0)
+ if (!(dsp->proc_mask_enabled & mask))
return NULL; /* Not enabled */
- struct dsp_proc_slot *s = dsp->proc_slots[1];
+ struct dsp_proc_slot *s = dsp->proc_slots;
- while (1) /* In proc_masks == it must be there */
+ while (1) /* In proc_mask_enabled == it must be there */
{
- if (BIT_N(s->db_entry->id) == mask)
+ if (BIT_N(proc_db_entry(s)->id) == mask)
return s;
- s = s->next[1];
+ s = s->next;
}
}
@@ -94,54 +105,23 @@ static intptr_t proc_broadcast(struct dsp_config *dsp, unsigned int setting,
intptr_t value)
{
bool multi = setting < DSP_PROC_SETTING;
- struct dsp_proc_slot *s = multi ?
- dsp->proc_slots[1] : find_proc_slot(dsp, setting - DSP_PROC_SETTING);
+ struct dsp_proc_slot *s = multi ? dsp->proc_slots :
+ find_proc_slot(dsp, setting - DSP_PROC_SETTING);
while (s != NULL)
{
- intptr_t ret = s->db_entry->configure(&s->proc_entry, dsp, setting,
- value);
+ intptr_t ret = proc_db_entry(s)->configure(
+ &s->proc_entry, dsp, setting, value);
+
if (!multi)
return ret;
- s = s->next[1];
+ s = s->next;
}
return multi ? 1 : 0;
}
-/* Generic handler for this->process[0] */
-static void dsp_process_null(struct dsp_proc_entry *this,
- struct dsp_buffer **buf_p)
-{
- (void)this; (void)buf_p;
-}
-
-/* Generic handler for this->process[1] */
-static void dsp_format_change_process(struct dsp_proc_entry *this,
- struct dsp_buffer **buf_p)
-{
- enum dsp_proc_ids id =
- TYPE_FROM_MEMBER(struct dsp_proc_slot, this, proc_entry)->db_entry->id;
-
- DSP_PRINT_FORMAT(<Default Handler>, id, (*buf_p)->format);
-
- /* We don't keep back references to the DSP, so just search for it */
- struct dsp_config *dsp;
- for (unsigned int i = 0; (dsp = dsp_get_config(i)); i++)
- {
- /* Found one with the id, check if it's this one
- (NULL return doesn't matter) */
- if (&find_proc_slot(dsp, id)->proc_entry == this)
- {
- if (dsp_proc_active(dsp, id))
- dsp_proc_call(this, buf_p, 0);
-
- break;
- }
- }
-}
-
/* Add an item to the enabled list */
static struct dsp_proc_slot *
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)
return NULL;
}
- const struct dsp_proc_db_entry *db_entry_prev = NULL;
- const struct dsp_proc_db_entry *db_entry;
+ unsigned int db_index = 0, db_index_prev = DSP_NUM_PROC_STAGES;
/* Order of enabled list is same as DB array */
- for (unsigned int i = 0;; i++)
+ while (1)
{
- if (i >= DSP_NUM_PROC_STAGES)
- return NULL;
-
- db_entry = dsp_proc_database[i];
-
- uint32_t m = BIT_N(db_entry->id);
+ uint32_t m = BIT_N(dsp_proc_database[db_index]->id);
if (m == mask)
break; /* This is the one */
- if (dsp->proc_masks[1] & m)
- db_entry_prev = db_entry;
+ if (dsp->proc_mask_enabled & m)
+ db_index_prev = db_index;
+
+ if (++db_index >= DSP_NUM_PROC_STAGES)
+ return NULL;
}
struct dsp_proc_slot *s = &dsp_proc_slot_arr[slot];
- if (db_entry_prev != NULL)
+ if (db_index_prev < DSP_NUM_PROC_STAGES)
{
- struct dsp_proc_slot *prev = find_proc_slot(dsp, db_entry_prev->id);
- s->next[0] = prev->next[0];
- s->next[1] = prev->next[1];
- prev->next[1] = s;
+ struct dsp_proc_slot *prev =
+ find_proc_slot(dsp, dsp_proc_database[db_index_prev]->id);
+ s->next = prev->next;
+ prev->next = s;
}
else
{
- s->next[0] = dsp->proc_slots[0];
- s->next[1] = dsp->proc_slots[1];
- dsp->proc_slots[1] = s;
+ s->next = dsp->proc_slots;
+ dsp->proc_slots = s;
}
- s->db_entry = db_entry; /* record DB entry */
- dsp->proc_masks[1] |= mask;
+ s->mask = mask | NACT_BIT;
+ s->version = 0;
+ s->db_index = db_index;
+ dsp->proc_mask_enabled |= mask;
dsp->slot_free_mask &= ~BIT_N(slot);
return s;
@@ -203,33 +181,33 @@ dsp_proc_enable_enlink(struct dsp_config *dsp, uint32_t mask)
static struct dsp_proc_slot *
dsp_proc_enable_delink(struct dsp_config *dsp, uint32_t mask)
{
- struct dsp_proc_slot *s = dsp->proc_slots[1];
+ struct dsp_proc_slot *s = dsp->proc_slots;
struct dsp_proc_slot *prev = NULL;
- while (1) /* In proc_masks == it must be there */
+ while (1) /* In proc_mask_enabled == it must be there */
{
- if (BIT_N(s->db_entry->id) == mask)
+ if (BIT_N(proc_db_entry(s)->id) == mask)
{
if (prev)
- prev->next[1] = s->next[1];
+ prev->next = s->next;
else
- dsp->proc_slots[1] = s->next[1];
+ dsp->proc_slots = s->next;
- dsp->proc_masks[1] &= ~mask;
+ dsp->proc_mask_enabled &= ~mask;
dsp->slot_free_mask |= BIT_N(s - dsp_proc_slot_arr);
return s;
}
prev = s;
- s = s->next[1];
+ s = s->next;
}
}
void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id,
bool enable)
{
- uint32_t mask = BIT_N(id);
- bool enabled = dsp->proc_masks[1] & mask;
+ const uint32_t mask = BIT_N(id);
+ bool enabled = dsp->proc_mask_enabled & mask;
if (enable)
{
@@ -247,13 +225,11 @@ void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id,
{
/* New entry - set defaults */
s->proc_entry.data = 0;
- s->proc_entry.ip_mask = mask;
- s->proc_entry.process[0] = dsp_process_null;
- s->proc_entry.process[1] = dsp_format_change_process;
+ s->proc_entry.process = NULL;
}
- enabled = s->db_entry->configure(&s->proc_entry, dsp, DSP_PROC_INIT,
- enabled) >= 0;
+ enabled = proc_db_entry(s)->configure(&s->proc_entry, dsp,
+ DSP_PROC_INIT, enabled) >= 0;
if (enabled)
return;
@@ -267,38 +243,7 @@ void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id,
dsp_proc_activate(dsp, id, false); /* Deactivate it first */
struct dsp_proc_slot *s = dsp_proc_enable_delink(dsp, mask);
- s->db_entry->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0);
-}
-
-/* Maintain the list structure for the active list where each enabled entry
- * has a link to the next active item, even if not active which facilitates
- * switching out of format change mode by a stage during a format change.
- * When that happens, the iterator must jump over inactive but enabled
- * stages after its current position. */
-static struct dsp_proc_slot *
-dsp_proc_activate_link(struct dsp_config *dsp, uint32_t mask,
- struct dsp_proc_slot *s)
-{
- uint32_t m = BIT_N(s->db_entry->id);
- uint32_t mor = m | mask;
-
- if (mor == m) /* Only if same single bit in common */
- {
- dsp->proc_masks[0] |= mask;
- return s;
- }
- else if (~mor == 0) /* Only if bits complement */
- {
- dsp->proc_masks[0] &= mask;
- return s->next[0];
- }
-
- struct dsp_proc_slot *next = s->next[1];
- next = dsp_proc_activate_link(dsp, mask, next);
-
- s->next[0] = next;
-
- return (m & dsp->proc_masks[0]) ? s : next;
+ proc_db_entry(s)->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0);
}
/* Activate or deactivate a stage */
@@ -307,55 +252,109 @@ void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id,
{
const uint32_t mask = BIT_N(id);
- if (!(dsp->proc_masks[1] & mask))
+ if (!(dsp->proc_mask_enabled & mask))
return; /* Not enabled */
- if (activate != !(dsp->proc_masks[0] & mask))
+ if (activate != !(dsp->proc_mask_active & mask))
return; /* No change in state */
- /* Send mask bit if activating and ones complement if deactivating */
- dsp->proc_slots[0] = dsp_proc_activate_link(
- dsp, activate ? mask : ~mask, dsp->proc_slots[1]);
+ struct dsp_proc_slot *s = find_proc_slot(dsp, id);
+
+ if (activate)
+ {
+ dsp->proc_mask_active |= mask;
+ s->mask &= ~NACT_BIT;
+ }
+ else
+ {
+ dsp->proc_mask_active &= ~mask;
+ s->mask |= NACT_BIT;
+ }
}
/* Is the stage specified by the id currently active? */
bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id)
{
- return (dsp->proc_masks[0] & BIT_N(id)) != 0;
+ return (dsp->proc_mask_active & BIT_N(id)) != 0;
}
-/* Determine by the rules if the processing function should be called */
-static FORCE_INLINE bool dsp_proc_should_call(struct dsp_proc_entry *this,
- struct dsp_buffer *buf,
- unsigned int fmt)
+/* Force the specified stage to receive a format update before the next
+ * buffer is sent to process() */
+void dsp_proc_want_format_update(struct dsp_config *dsp,
+ enum dsp_proc_ids id)
{
- uint32_t ip_mask = this->ip_mask;
+ struct dsp_proc_slot *s = find_proc_slot(dsp, id);
- return UNLIKELY(fmt != 0) || /* Also pass override value */
- ip_mask == 0 || /* Not in-place */
- ((ip_mask & buf->proc_mask) == 0 &&
- (buf->proc_mask |= ip_mask, buf->remcount > 0));
+ if (s)
+ s->version = 0; /* Set invalid */
}
-/* Call this->process[fmt] according to the rules (for external call) */
-bool dsp_proc_call(struct dsp_proc_entry *this, struct dsp_buffer **buf_p,
- unsigned int fmt)
+/* Set or unset in-place operation */
+void dsp_proc_set_in_place(struct dsp_config *dsp, enum dsp_proc_ids id,
+ bool in_place)
{
- if (dsp_proc_should_call(this, *buf_p, fmt))
+ struct dsp_proc_slot *s = find_proc_slot(dsp, id);
+
+ if (!s)
+ return;
+
+ const uint32_t mask = BIT_N(id);
+
+ if (in_place)
+ s->mask |= mask;
+ else
+ s->mask &= ~mask;
+}
+
+/* Determine by the rules if the processing function should be called */
+static NO_INLINE bool dsp_proc_new_format(struct dsp_proc_slot *s,
+ struct dsp_config *dsp,
+ struct dsp_buffer *buf)
+{
+ struct dsp_proc_entry *this = &s->proc_entry;
+ struct sample_format *format = &buf->format;
+
+ switch (proc_db_entry(s)->configure(
+ this, dsp, DSP_PROC_NEW_FORMAT, (intptr_t)format))
{
- this->process[fmt == (0u-1u) ? 0 : fmt](this, buf_p);
+ case PROC_NEW_FORMAT_OK:
+ s->version = format->version;
return true;
- }
- return false;
+ case PROC_NEW_FORMAT_TRANSITION:
+ return true;
+
+ case PROC_NEW_FORMAT_DEACTIVATED:
+ s->version = format->version;
+ return false;
+
+ default:
+ return false;
+ }
}
-#ifndef DSP_PROCESS_START
-/* These do nothing if not previously defined */
-#define DSP_PROCESS_START()
-#define DSP_PROCESS_LOOP()
-#define DSP_PROCESS_END()
-#endif /* !DSP_PROCESS_START */
+static FORCE_INLINE void dsp_proc_call(struct dsp_proc_slot *s,
+ struct dsp_config *dsp,
+ struct dsp_buffer **buf_p)
+{
+ struct dsp_buffer *buf = *buf_p;
+
+ if (UNLIKELY(buf->format.version != s->version))
+ {
+ if (!dsp_proc_new_format(s, dsp, buf))
+ return;
+ }
+
+ if (s->mask)
+ {
+ if ((s->mask & (buf->proc_mask | NACT_BIT)) || buf->remcount <= 0)
+ return;
+
+ buf->proc_mask |= s->mask;
+ }
+
+ s->proc_entry.process(&s->proc_entry, buf_p);
+}
/**
* dsp_process:
@@ -411,9 +410,6 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src,
}
DSP_PROCESS_START();
-#if 0 /* Not needed now but enable if something must know this */
- dsp->processing = true;
-#endif
/* Tag input with codec-specified sample format */
src->format = dsp->io_data.format;
@@ -423,36 +419,29 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src,
/* Out-of-place-processing stages take the current buf as input
* and switch the buffer to their own output buffer */
struct dsp_buffer *buf = src;
- unsigned int fmt = buf->format.changed;
- /* Convert input samples to internal format */
- dsp->io_data.input_samples[fmt](&dsp->io_data, &buf);
- fmt = buf->format.changed;
+ if (UNLIKELY(buf->format.version != dsp->io_data.sample_buf.format.version))
+ dsp_sample_input_format_change(&dsp->io_data, &buf->format);
- struct dsp_proc_slot *s = dsp->proc_slots[fmt];
+ /* Convert input samples to internal format */
+ dsp->io_data.input_samples(&dsp->io_data, &buf);
/* Call all active/enabled stages depending if format is
same/changed on the last output buffer */
- while (s != NULL)
- {
- if (dsp_proc_should_call(&s->proc_entry, buf, fmt))
- {
- s->proc_entry.process[fmt](&s->proc_entry, &buf);
- fmt = buf->format.changed;
- }
-
- /* The buffer may have changed along with the format flag */
- s = s->next[fmt];
- }
+ for (struct dsp_proc_slot *s = dsp->proc_slots; s; s = s->next)
+ dsp_proc_call(s, dsp, &buf);
/* Don't overread/write src/destination */
int outcount = MIN(dst->bufcount, buf->remcount);
- if (fmt == 0 && outcount <= 0)
+ if (outcount <= 0)
break; /* Output full or purged internal buffers */
+ if (UNLIKELY(buf->format.version != dsp->io_data.output_version))
+ dsp_sample_output_format_change(&dsp->io_data, &buf->format);
+
dsp->io_data.outcount = outcount;
- dsp->io_data.output_samples[fmt](&dsp->io_data, buf, dst);
+ dsp->io_data.output_samples(&dsp->io_data, buf, dst);
/* Advance buffers by what output consumed and produced */
dsp_advance_buffer32(buf, outcount);
@@ -461,10 +450,6 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src,
DSP_PROCESS_LOOP();
} /* while */
-#if 0 /* Not needed now but enable if something must know this */
- dsp->process = false;
-#endif
-
DSP_PROCESS_END();
}
@@ -495,13 +480,6 @@ enum dsp_ids dsp_get_id(const struct dsp_config *dsp)
return (enum dsp_ids)id;
}
-#if 0 /* Not needed now but enable if something must know this */
-bool dsp_is_busy(const struct dsp_config *dsp)
-{
- return dsp->processing;
-}
-#endif /* 0 */
-
/* Do what needs initializing before enable/disable calls can be made.
* Must be done before changing settings for the first time. */
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
DSP_SET_SAMPLE_DEPTH,
DSP_SET_STEREO_MODE,
DSP_FLUSH,
+ DSP_SET_PITCH,
DSP_PROC_INIT,
DSP_PROC_CLOSE,
+ DSP_PROC_NEW_FORMAT,
DSP_PROC_SETTING, /* stage-specific should be this + id */
};
@@ -54,10 +56,13 @@ enum dsp_stereo_modes
STEREO_NUM_MODES,
};
-/* Format into for the buffer (if .valid == true) */
+/* Format into for the buffer */
struct sample_format
{
- uint8_t changed; /* 00h: 0=no change, 1=changed (is also index) */
+ uint8_t version; /* 00h: format version number (never == 0,
+ 0 is used to detect format calls for
+ individual stages, such as when they
+ are newly enabled) */
uint8_t num_channels; /* 01h: number of channels of data */
uint8_t frac_bits; /* 02h: number of fractional bits */
uint8_t output_scale; /* 03h: output scaling shift */
@@ -66,16 +71,6 @@ struct sample_format
/* 0ch */
};
-/* Compare format data only */
-#define EQU_SAMPLE_FORMAT(f1, f2) \
- (!memcmp(&(f1).num_channels, &(f2).num_channels, \
- sizeof (f1) - sizeof ((f1).changed)))
-
-static inline void format_change_set(struct sample_format *f)
- { f->changed = 1; }
-static inline void format_change_ack(struct sample_format *f)
- { f->changed = 0; }
-
/* Used by ASM routines - keep field order or else fix the functions */
struct dsp_buffer
{
@@ -133,30 +128,12 @@ static inline void dsp_advance_buffer32(struct dsp_buffer *buf,
buf->p32[1] += by_count;
}
-/** For use by processing stages **/
-
-#define DSP_PRINT_FORMAT(name, id, format) \
- DEBUGF("DSP format- " #name "\n" \
- " id:%d chg:%c ch:%u fb:%u os:%u hz:%u chz:%u\n", \
- (int)id, \
- (format).changed ? 'y' : 'n', \
- (unsigned int)(format).num_channels, \
- (unsigned int)(format).frac_bits, \
- (unsigned int)(format).output_scale, \
- (unsigned int)(format).frequency, \
- (unsigned int)(format).codec_frequency);
-
/* Get DSP pointer */
struct dsp_config * dsp_get_config(enum dsp_ids id);
/* Get DSP id */
enum dsp_ids dsp_get_id(const struct dsp_config *dsp);
-#if 0 /* Not needed now but enable if something must know this */
-/* Is the DSP processing a buffer? */
-bool dsp_is_busy(const struct dsp_config *dsp);
-#endif /* 0 */
-
/** General DSP processing **/
/* 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 @@
#include "fixedpoint.h"
#include "replaygain.h"
#include "dsp_proc_entry.h"
-#include "dsp_sample_io.h"
#include "dsp_misc.h"
#include "pga.h"
#include "channel_mode.h"
@@ -113,20 +112,21 @@ static int32_t pitch_ratio = PITCH_SPEED_100;
static void dsp_pitch_update(struct dsp_config *dsp)
{
- /* Account for playback speed adjustment when setting dsp->frequency
- if we're called from the main audio thread. Voice playback thread
- does not support this feature. */
- struct sample_io_data *data = (void *)dsp;
- data->format.frequency =
- (int64_t)pitch_ratio * data->format.codec_frequency / PITCH_SPEED_100;
+ dsp_configure(dsp, DSP_SET_PITCH,
+ fp_div(pitch_ratio, PITCH_SPEED_100, 16));
}
static void dsp_set_pitch(int32_t percent)
{
- pitch_ratio = percent > 0 ? percent : PITCH_SPEED_100;
- struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
- struct sample_io_data *data = (void *)dsp;
- dsp_configure(dsp, DSP_SWITCH_FREQUENCY, data->format.codec_frequency);
+ if (percent <= 0)
+ percent = PITCH_SPEED_100;
+
+ if (percent == pitch_ratio)
+ return;
+
+ pitch_ratio = percent;
+
+ dsp_pitch_update(dsp_get_config(CODEC_IDX_AUDIO));
}
#endif /* HAVE_PITCHCONTROL */
@@ -173,6 +173,13 @@ int dsp_callback(int msg, intptr_t param)
return retval;
}
+static void INIT_ATTR misc_dsp_init(struct dsp_config *dsp,
+ enum dsp_ids dsp_id)
+{
+ /* Enable us for the audio DSP at startup */
+ if (dsp_id == CODEC_IDX_AUDIO)
+ dsp_proc_enable(dsp, DSP_PROC_MISC_HANDLER, true);
+}
/* This is a null-processing stage that monitors as an enabled stage but never
* becomes active in processing samples. It only hooks messages. */
@@ -186,9 +193,7 @@ static intptr_t misc_handler_configure(struct dsp_proc_entry *this,
switch (setting)
{
case DSP_INIT:
- /* Enable us for the audio DSP at startup */
- if (value == CODEC_IDX_AUDIO)
- dsp_proc_enable(dsp, DSP_PROC_MISC_HANDLER, true);
+ misc_dsp_init(dsp, (enum dsp_ids)value);
break;
case DSP_PROC_CLOSE:
@@ -212,7 +217,7 @@ static intptr_t misc_handler_configure(struct dsp_proc_entry *this,
#endif
}
- return 1;
+ return 0;
(void)this;
}
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;
#define DSP_PROC_DB_START \
enum dsp_proc_ids \
{ \
- ___DSP_PROC_ID_FIRST = -1,
+ ___DSP_PROC_ID_RESERVED = 0,
#define DSP_PROC_DB_ITEM(name) \
DSP_PROC_##name,
@@ -102,19 +102,24 @@ typedef void (*dsp_proc_fn_type)(struct dsp_proc_entry *this,
* The structure allocated to every stage when enabled.
*
* default settings:
- * .data = 0
- * .ip_mask = BIT_N(dsp_proc_db_entry.id)
- * .process[0] = dsp_process_null
- * .process[1] = dsp_format_change_process
+ * .data = 0
+ * .process = NULL
*
* DSP_PROC_INIT handler just has to change what it needs to change. It may
* also be modified at any time to implement the stage's demands.
*/
struct dsp_proc_entry
{
- intptr_t data; /* 00h: any value, at beginning for easy asm use */
- uint32_t ip_mask; /* In-place id bit (0 or id bit flag if in-place) */
- dsp_proc_fn_type process[2]; /* Processing normal/format changes */
+ intptr_t data; /* 00h: any value, used by asm */
+ dsp_proc_fn_type process; /* Processing vector */
+};
+
+/* Return values for DSP_PROC_NEW_FORMAT setting */
+enum
+{
+ PROC_NEW_FORMAT_OK = 0, /* Acks, calls process() (default) */
+ PROC_NEW_FORMAT_DEACTIVATED, /* Acks, does not call process() */
+ PROC_NEW_FORMAT_TRANSITION /* Does not ack, calls process() */
};
/* DSP transform configure function prototype */
@@ -137,10 +142,24 @@ void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id,
/* Is the specified stage active on the DSP? */
bool dsp_proc_active(struct dsp_config *dsp, enum dsp_proc_ids id);
-/* Call this->process[fmt] according to the rules
- * pass (unsigned)-1 to call function 0 with no restriction */
-bool dsp_proc_call(struct dsp_proc_entry *this, struct dsp_buffer **buf_p,
- unsigned int fmt);
+/* Force the specified stage to receive a format update before the next
+ * buffer is sent to process() */
+void dsp_proc_want_format_update(struct dsp_config *dsp,
+ enum dsp_proc_ids id);
+
+/* Set or unset in-place operation */
+void dsp_proc_set_in_place(struct dsp_config *dsp, enum dsp_proc_ids id,
+ bool in_place);
+
+#define DSP_PRINT_FORMAT(id, format) \
+ DEBUGF("DSP format- " #id "\n" \
+ " ver:%u ch:%u fb:%u os:%u hz:%u chz:%u\n", \
+ (unsigned int)(format).version \
+ (unsigned int)(format).num_channels, \
+ (unsigned int)(format).frac_bits, \
+ (unsigned int)(format).output_scale, \
+ (unsigned int)(format).frequency, \
+ (unsigned int)(format).codec_frequency);
struct dsp_proc_db_entry
{
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 @@
****************************************************************************/
#include "config.h"
#include "system.h"
+#include "fixedpoint.h"
#include "dsp_core.h"
#include "dsp_sample_io.h"
+#include "dsp_proc_entry.h"
-#if 1
-#include <debug.h>
-#else
+#if 0
#undef DEBUGF
#define DEBUGF(...)
#endif
@@ -50,6 +50,8 @@
extern void dsp_sample_output_init(struct sample_io_data *this);
extern void dsp_sample_output_flush(struct sample_io_data *this);
+extern void dsp_sample_output_format_change(struct sample_io_data *this,
+ struct sample_format *format);
#define SAMPLE_BUF_COUNT 128 /* Per channel, per DSP */
/* 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,
int count = MIN(s->remcount, SAMPLE_BUF_COUNT);
d->remcount = count;
- d->p32[0] = this->sample_buf_arr[0];
- d->p32[1] = this->sample_buf_arr[channels - 1];
+ d->p32[0] = this->sample_buf_p[0];
+ d->p32[1] = this->sample_buf_p[channels - 1];
d->proc_mask = s->proc_mask;
return count;
@@ -210,9 +212,9 @@ static void sample_input_ni_stereo32(struct sample_io_data *this,
}
/* set the to-native sample conversion function based on dsp sample
- * parameters */
-static void dsp_sample_input_format_change(struct sample_io_data *this,
- struct dsp_buffer **buf_p)
+ * parameters - depends upon stereo_mode and sample_depth */
+void dsp_sample_input_format_change(struct sample_io_data *this,
+ struct sample_format *format)
{
static const sample_input_fn_type fns[STEREO_NUM_MODES][2] =
{
@@ -227,33 +229,35 @@ static void dsp_sample_input_format_change(struct sample_io_data *this,
sample_input_mono32 },
};
- struct dsp_buffer *src = *buf_p;
- struct dsp_buffer *dst = &this->sample_buf;
-
- /* Ack configured format change */
- format_change_ack(&this->format);
+ if (this->sample_buf.remcount > 0)
+ return;
- if (dst->remcount > 0)
- {
- *buf_p = dst;
- return; /* data still remains */
- }
+ DSP_PRINT_FORMAT(DSP Input, this->format);
- DSP_PRINT_FORMAT(DSP Input, -1, src->format);
+ this->format_dirty = 0;
+ this->sample_buf.format = *format;
+ this->input_samples = fns[this->stereo_mode]
+ [this->sample_depth > NATIVE_DEPTH ? 1 : 0];
+}
- /* new format - remember it and pass it along */
- dst->format = src->format;
- this->input_samples[0] = fns[this->stereo_mode]
- [this->sample_depth > NATIVE_DEPTH ? 1 : 0];
+/* increment the format version counter */
+static void format_change_set(struct sample_io_data *this)
+{
+ if (this->format_dirty)
+ return;
- this->input_samples[0](this, buf_p);
+ this->format.version = (uint8_t)(this->format.version + 1) ?: 1;
+ this->format_dirty = 1;
+}
- if (*buf_p == dst) /* buffer switch? */
- format_change_ack(&src->format);
+/* discard the sample buffer */
+static void dsp_sample_input_flush(struct sample_io_data *this)
+{
+ this->sample_buf.remcount = 0;
}
-static void dsp_sample_input_init(struct sample_io_data *this,
- enum dsp_ids dsp_id)
+static void INIT_ATTR dsp_sample_input_init(struct sample_io_data *this,
+ enum dsp_ids dsp_id)
{
int32_t *lbuf, *rbuf;
@@ -274,17 +278,15 @@ static void dsp_sample_input_init(struct sample_io_data *this,
return;
}
- this->sample_buf_arr[0] = lbuf;
- this->sample_buf_arr[1] = rbuf;
-
- this->input_samples[0] = sample_input_ni_stereo32;
- this->input_samples[1] = dsp_sample_input_format_change;
+ this->sample_buf_p[0] = lbuf;
+ this->sample_buf_p[1] = rbuf;
}
-/* discard the sample buffer */
-static void dsp_sample_input_flush(struct sample_io_data *this)
+static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this,
+ enum dsp_ids dsp_id)
{
- this->sample_buf.remcount = 0;
+ dsp_sample_input_init(this, dsp_id);
+ dsp_sample_output_init(this);
}
void dsp_sample_io_configure(struct sample_io_data *this,
@@ -294,13 +296,12 @@ void dsp_sample_io_configure(struct sample_io_data *this,
switch (setting)
{
case DSP_INIT:
- dsp_sample_input_init(this, (enum dsp_ids)value);
- dsp_sample_output_init(this);
+ dsp_sample_io_init(this, (enum dsp_ids)value);
break;
case DSP_RESET:
/* Reset all sample descriptions to default */
- format_change_set(&this->format);
+ format_change_set(this);
this->format.num_channels = 2;
this->format.frac_bits = WORD_FRACBITS;
this->format.output_scale = WORD_FRACBITS + 1 - NATIVE_DEPTH;
@@ -311,14 +312,14 @@ void dsp_sample_io_configure(struct sample_io_data *this,
break;
case DSP_SET_FREQUENCY:
+ format_change_set(this);
value = value > 0 ? value : NATIVE_FREQUENCY;
- format_change_set(&this->format);
this->format.frequency = value;
this->format.codec_frequency = value;
break;
case DSP_SET_SAMPLE_DEPTH:
- format_change_set(&this->format);
+ format_change_set(this);
this->format.frac_bits =
value <= NATIVE_DEPTH ? WORD_FRACBITS : value;
this->format.output_scale =
@@ -327,7 +328,7 @@ void dsp_sample_io_configure(struct sample_io_data *this,
break;
case DSP_SET_STEREO_MODE:
- format_change_set(&this->format);
+ format_change_set(this);
this->format.num_channels = value == STEREO_MONO ? 1 : 2;
this->stereo_mode = value;
break;
@@ -336,5 +337,12 @@ void dsp_sample_io_configure(struct sample_io_data *this,
dsp_sample_input_flush(this);
dsp_sample_output_flush(this);
break;
+
+ case DSP_SET_PITCH:
+ format_change_set(this);
+ value = value > 0 ? value : (1 << 16);
+ this->format.frequency =
+ fp_mul(value, this->format.codec_frequency, 16);
+ break;
}
}
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,
/* This becomes part of the DSP aggregate */
struct sample_io_data
{
- int outcount; /* 00h: Output count */
- struct sample_format format; /* General format info */
- int sample_depth; /* Codec-specified sample depth */
- int stereo_mode; /* Codec-specified input format */
- sample_input_fn_type input_samples[2]; /* input functions */
+ int outcount; /* 00h: Output count */
+ struct sample_format format; /* Format for next dsp_process call */
+ int sample_depth; /* Codec-specified sample depth */
+ int stereo_mode; /* Codec-specified channel format */
+ sample_input_fn_type input_samples; /* Initial input function */
struct dsp_buffer sample_buf; /* Buffer descriptor for converted samples */
- int32_t *sample_buf_arr[2]; /* Internal format buffer pointers */
- sample_output_fn_type output_samples[2]; /* Final output functions */
+ int32_t *sample_buf_p[2]; /* Internal format buffer pointers */
+ sample_output_fn_type output_samples; /* Final output function */
+ uint8_t format_dirty; /* Format change set, avoids superfluous
+ increments before carrying it out */
+ uint8_t output_version; /* Format version of src buffer at output */
};
+void dsp_sample_input_format_change(struct sample_io_data *this,
+ struct sample_format *format);
+
+void dsp_sample_output_format_change(struct sample_io_data *this,
+ struct sample_format *format);
+
/* Sample IO watches the format setting from the codec */
void dsp_sample_io_configure(struct sample_io_data *this,
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 @@
#include "system.h"
#include "dsp_core.h"
#include "dsp_sample_io.h"
+#include "dsp_proc_entry.h"
#include "dsp-util.h"
#include <string.h>
@@ -159,9 +160,8 @@ void sample_output_dithered(struct sample_io_data *this,
}
/* Initialize the output function for settings and format */
-static void dsp_sample_output_format_change(struct sample_io_data *this,
- struct dsp_buffer *src,
- struct dsp_buffer *dst)
+void dsp_sample_output_format_change(struct sample_io_data *this,
+ struct sample_format *format)
{
static const sample_output_fn_type fns[2][2] =
{
@@ -171,25 +171,20 @@ static void dsp_sample_output_format_change(struct sample_io_data *this,
sample_output_dithered },
};
- struct sample_format *format = &src->format;
bool dither = dsp_get_id((void *)this) == CODEC_IDX_AUDIO &&
dither_data.enabled;
int channels = format->num_channels;
- DSP_PRINT_FORMAT(DSP Output, -1, *format);
+ DSP_PRINT_FORMAT(DSP Output, *format);
- this->output_samples[0] = fns[dither ? 1 : 0][channels - 1];
- format_change_ack(format); /* always ack, we're last */
-
- /* The real function mustn't be called with no data */
- if (this->outcount > 0)
- this->output_samples[0](this, src, dst);
+ this->output_samples = fns[dither ? 1 : 0][channels - 1];
+ this->output_version = format->version;
}
-void dsp_sample_output_init(struct sample_io_data *this)
+void INIT_ATTR dsp_sample_output_init(struct sample_io_data *this)
{
- this->output_samples[0] = sample_output_stereo;
- this->output_samples[1] = dsp_sample_output_format_change;
+ this->output_version = 0;
+ this->output_samples = sample_output_stereo;
}
/* Flush the dither history */
@@ -199,6 +194,7 @@ void dsp_sample_output_flush(struct sample_io_data *this)
memset(dither_data.state, 0, sizeof (dither_data.state));
}
+
/** Output settings **/
/* Set the tri-pdf dithered output */
@@ -207,8 +203,11 @@ void dsp_dither_enable(bool enable)
if (enable == dither_data.enabled)
return;
- struct sample_io_data *data = (void *)dsp_get_config(CODEC_IDX_AUDIO);
- dsp_sample_output_flush(data);
dither_data.enabled = enable;
- data->output_samples[0] = dsp_sample_output_format_change;
+ struct sample_io_data *data = (void *)dsp_get_config(CODEC_IDX_AUDIO);
+
+ if (enable)
+ dsp_sample_output_flush(data);
+
+ data->output_version = 0; /* Force format update */
}
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,
{
case DSP_PROC_INIT:
if (value != 0)
- break;
- this->process[0] = eq_process;
+ break; /* Already enabled */
+
+ this->process = eq_process;
+ /* Fall-through */
case DSP_PROC_CLOSE:
pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT);
break;
@@ -167,7 +169,7 @@ static intptr_t eq_configure(struct dsp_proc_entry *this,
break;
}
- return 1;
+ return 0;
(void)dsp;
}
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
int32_t last_sample[2]; /* 08h: Last samples for interpolation (L+R) */
/* 10h */
int32_t frequency; /* Virtual samplerate */
- struct dsp_config *dsp; /* The DSP for this resampler */
struct dsp_buffer resample_buf; /* Buffer descriptor for resampled data */
- int32_t *resample_buf_arr[2]; /* Actual output data pointers */
+ int32_t *resample_out_p[2]; /* Actual output buffer pointers */
} resample_data[DSP_COUNT] IBSS_ATTR;
/* Actual worker function. Implemented here or in target assembly code. */
@@ -75,9 +74,9 @@ static void lin_resample_flush(struct dsp_proc_entry *this)
}
static bool lin_resample_new_delta(struct resample_data *data,
- struct dsp_buffer *buf)
+ struct sample_format *format)
{
- int32_t frequency = buf->format.frequency; /* virtual samplerate */
+ int32_t frequency = format->frequency; /* virtual samplerate */
data->frequency = frequency;
data->delta = fp_div(frequency, NATIVE_FREQUENCY, 16);
@@ -169,8 +168,8 @@ static void lin_resample_process(struct dsp_proc_entry *this,
return; /* data still remains */
dst->remcount = 0;
- dst->p32[0] = data->resample_buf_arr[0];
- dst->p32[1] = data->resample_buf_arr[1];
+ dst->p32[0] = data->resample_out_p[0];
+ dst->p32[1] = data->resample_out_p[1];
if (src->remcount > 0)
{
@@ -189,63 +188,44 @@ static void lin_resample_process(struct dsp_proc_entry *this,
}
/* Finish draining old samples then switch format or shut off */
-static void lin_resample_new_format(struct dsp_proc_entry *this,
- struct dsp_buffer **buf_p)
+static intptr_t lin_resample_new_format(struct dsp_proc_entry *this,
+ struct dsp_config *dsp,
+ struct sample_format *format)
{
struct resample_data *data = (void *)this->data;
- struct dsp_buffer *src = *buf_p;
struct dsp_buffer *dst = &data->resample_buf;
if (dst->remcount > 0)
- {
- *buf_p = dst;
- return; /* data still remains */
- }
+ return PROC_NEW_FORMAT_TRANSITION;
- DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, DSP_PROC_RESAMPLE, src->format);
+ DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, *format);
- struct dsp_config *dsp = data->dsp;
int32_t frequency = data->frequency;
bool active = dsp_proc_active(dsp, DSP_PROC_RESAMPLE);
- if (src->format.frequency != frequency)
+ if (format->frequency != frequency)
{
DEBUGF(" DSP_PROC_RESAMPLE- new delta\n");
- active = lin_resample_new_delta(data, src);
+ active = lin_resample_new_delta(data, format);
dsp_proc_activate(dsp, DSP_PROC_RESAMPLE, active);
}
/* Everything after us is NATIVE_FREQUENCY */
- struct sample_format f = src->format;
- f.frequency = NATIVE_FREQUENCY;
- f.codec_frequency = NATIVE_FREQUENCY;
-
- if (!active)
- {
- DEBUGF(" DSP_PROC_RESAMPLE- not active\n");
- dst->format = f; /* Keep track */
- return; /* No resampling required */
- }
-
- format_change_ack(&src->format);
+ dst->format = *format;
+ dst->format.frequency = NATIVE_FREQUENCY;
+ dst->format.codec_frequency = NATIVE_FREQUENCY;
- if (EQU_SAMPLE_FORMAT(f, dst->format))
- {
- DEBUGF(" DSP_PROC_RESAMPLE- same dst format\n");
- format_change_ack(&f); /* Nothing changed that matters downstream */
- }
+ if (active)
+ return PROC_NEW_FORMAT_OK;
- dst->format = f;
- dsp_proc_call(this, buf_p, 0);
+ /* No longer needed */
+ DEBUGF(" DSP_PROC_RESAMPLE- deactivated\n");
+ return PROC_NEW_FORMAT_DEACTIVATED;
}
-static void lin_resample_init(struct dsp_config *dsp,
- enum dsp_ids dsp_id)
+static void INIT_ATTR lin_resample_dsp_init(struct dsp_config *dsp,
+ enum dsp_ids dsp_id)
{
- /* Always enable resampler so that format changes may be monitored and
- * it self-activated when required */
- dsp_proc_enable(dsp, DSP_PROC_RESAMPLE, true);
-
int32_t *lbuf, *rbuf;
switch (dsp_id)
@@ -265,8 +245,19 @@ static void lin_resample_init(struct dsp_config *dsp,
return;
}
- resample_data[dsp_id].resample_buf_arr[0] = lbuf;
- resample_data[dsp_id].resample_buf_arr[1] = rbuf;
+ /* Always enable resampler so that format changes may be monitored and
+ * it self-activated when required */
+ dsp_proc_enable(dsp, DSP_PROC_RESAMPLE, true);
+ resample_data[dsp_id].resample_out_p[0] = lbuf;
+ resample_data[dsp_id].resample_out_p[1] = rbuf;
+}
+
+static void INIT_ATTR lin_resample_proc_init(struct dsp_proc_entry *this,
+ struct dsp_config *dsp)
+{
+ dsp_proc_set_in_place(dsp, DSP_PROC_RESAMPLE, false);
+ this->data = (intptr_t)&resample_data[dsp_get_id(dsp)];
+ this->process = lin_resample_process;
}
/* DSP message hook */
@@ -275,10 +266,12 @@ static intptr_t lin_resample_configure(struct dsp_proc_entry *this,
unsigned int setting,
intptr_t value)
{
+ intptr_t retval = 0;
+
switch (setting)
{
case DSP_INIT:
- lin_resample_init(dsp, (enum dsp_ids)value);
+ lin_resample_dsp_init(dsp, (enum dsp_ids)value);
break;
case DSP_FLUSH:
@@ -286,21 +279,21 @@ static intptr_t lin_resample_configure(struct dsp_proc_entry *this,
break;
case DSP_PROC_INIT:
- this->data = (intptr_t)&resample_data[dsp_get_id(dsp)];
- this->ip_mask = 0; /* Not in-place */
- this->process[0] = lin_resample_process;
- this->process[1] = lin_resample_new_format;
- ((struct resample_data *)this->data)->dsp = dsp;
+ lin_resample_proc_init(this, dsp);
break;
case DSP_PROC_CLOSE:
/* This stage should be enabled at all times */
DEBUGF("DSP_PROC_RESAMPLE- Error: Closing!\n");
break;
+
+ case DSP_PROC_NEW_FORMAT:
+ retval = lin_resample_new_format(this, dsp,
+ (struct sample_format *)value);
+ break;
}
- return 1;
- (void)value;
+ return retval;
}
/* 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,
{
case DSP_PROC_INIT:
if (value != 0)
- break; /* Already initialized */
+ break; /* Already enabled */
+
this->data = (intptr_t)&pga_data;
- this->process[0] = pga_process;
+ this->process = pga_process;
break;
}
- return 1;
+ return 0;
(void)dsp;
}
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
static struct tdspeed_state_s
{
struct dsp_proc_entry *this; /* this stage */
- struct dsp_config *dsp; /* the DSP we use */
int channels; /* number of audio channels */
int32_t samplerate; /* current samplerate of input data */
int32_t factor; /* stretch factor (perdecimille) */
@@ -131,6 +130,10 @@ static bool tdspeed_update(int32_t samplerate, int32_t factor)
st->samplerate = samplerate;
st->factor = factor;
+ /* just discard remaining input data */
+ st->ovl_size = 0;
+ st->ovl_shift = 0;
+
/* Check parameters */
if (factor == PITCH_SPEED_100)
return false;
@@ -161,10 +164,6 @@ static bool tdspeed_update(int32_t samplerate, int32_t factor)
st->shift_max = (st->dst_step > st->src_step) ?
st->dst_step : st->src_step;
- /* just discard remaining input data */
- st->ovl_size = 0;
- st->ovl_shift = 0;
-
st->ovl_buff[0] = overlap_buffer[0];
st->ovl_buff[1] = overlap_buffer[1]; /* ignored if mono */
@@ -378,17 +377,14 @@ skip:;
/** DSP interface **/
-static void tdspeed_process_new_format(struct dsp_proc_entry *this,
- struct dsp_buffer **buf_p);
-
/* Enable or disable the availability of timestretch */
void dsp_timestretch_enable(bool enabled)
{
if (enabled != !tdspeed_state.this)
return; /* No change */
- dsp_proc_enable(dsp_get_config(CODEC_IDX_AUDIO), DSP_PROC_TIMESTRETCH,
- enabled);
+ struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
+ dsp_proc_enable(dsp, DSP_PROC_TIMESTRETCH, enabled);
}
/* Set the timestretch ratio */
@@ -405,7 +401,8 @@ void dsp_set_timestretch(int32_t percent)
if (percent == st->factor)
return; /* no change */
- dsp_configure(st->dsp, TIMESTRETCH_SET_FACTOR, percent);
+ struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
+ dsp_configure(dsp, TIMESTRETCH_SET_FACTOR, percent);
}
/* Return the timestretch ratio */
@@ -459,27 +456,22 @@ static void tdspeed_process(struct dsp_proc_entry *this,
}
/* Process format changes and settings changes */
-static void tdspeed_process_new_format(struct dsp_proc_entry *this,
- struct dsp_buffer **buf_p)
+static intptr_t tdspeed_new_format(struct dsp_proc_entry *this,
+ struct dsp_config *dsp,
+ struct sample_format *format)
{
- struct dsp_buffer *src = *buf_p;
struct dsp_buffer *dst = &dsp_outbuf;
if (dst->remcount > 0)
- {
- *buf_p = dst;
- return; /* output remains from an earlier call */
- }
+ return PROC_NEW_FORMAT_TRANSITION;
- DSP_PRINT_FORMAT(DSP_PROC_TIMESTRETCH, DSP_PROC_TIMESTRETCH, src->format);
+ DSP_PRINT_FORMAT(DSP_PROC_TIMESTRETCH, *format);
+ bool active = dsp_proc_active(dsp, DSP_PROC_TIMESTRETCH);
struct tdspeed_state_s *st = &tdspeed_state;
- struct dsp_config *dsp = st->dsp;
- struct sample_format *format = &src->format;
int channels = format->num_channels;
- if (format->codec_frequency != st->samplerate ||
- !dsp_proc_active(dsp, DSP_PROC_TIMESTRETCH))
+ if (format->codec_frequency != st->samplerate)
{
/* relevent parameters are changing - all overlap will be discarded */
st->channels = channels;
@@ -489,17 +481,10 @@ static void tdspeed_process_new_format(struct dsp_proc_entry *this,
channels,
format->codec_frequency,
st->factor / 100, st->factor % 100);
- bool active = tdspeed_update(format->codec_frequency, st->factor);
+ active = tdspeed_update(format->codec_frequency, st->factor);
dsp_proc_activate(dsp, DSP_PROC_TIMESTRETCH, active);
-
- if (!active)
- {
- DEBUGF(" DSP_PROC_RESAMPLE- not active\n");
- dst->format = src->format; /* Keep track */
- return; /* no more for now */
- }
}
- else if (channels != st->channels)
+ else if (active && channels != st->channels)
{
/* channel count transistion - have to make old data in overlap
buffer compatible with new format */
@@ -525,20 +510,25 @@ static void tdspeed_process_new_format(struct dsp_proc_entry *this,
}
}
- struct sample_format f = *format;
- format_change_ack(format);
+ dst->format = *format;
- if (EQU_SAMPLE_FORMAT(f, dst->format))
- {
- DEBUGF(" DSP_PROC_TIMESTRETCH- same dst format\n");
- format_change_ack(&f); /* nothing changed that matters downstream */
- }
+ if (active)
+ return PROC_NEW_FORMAT_OK;
- dst->format = f;
+ /* Nothing to do */
+ DEBUGF(" DSP_PROC_RESAMPLE- deactivated\n");
+ return PROC_NEW_FORMAT_DEACTIVATED;
- /* return to normal processing */
- this->process[0] = tdspeed_process;
- dsp_proc_call(this, buf_p, 0);
+ (void)this;
+}
+
+static void INIT_ATTR tdspeed_dsp_init(struct tdspeed_state_s *st,
+ enum dsp_ids dsp_id)
+{
+ /* everything is at 100% until dsp_set_timestretch is called with
+ some other value and timestretch is enabled at the time */
+ if (dsp_id == CODEC_IDX_AUDIO)
+ st->factor = PITCH_SPEED_100;
}
/* DSP message hook */
@@ -547,15 +537,14 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
unsigned int setting,
intptr_t value)
{
+ intptr_t retval = 0;
+
struct tdspeed_state_s *st = &tdspeed_state;
switch (setting)
{
case DSP_INIT:
- /* everything is at 100% until dsp_set_timestretch is called with
- some other value and timestretch is enabled at the time */
- if (value == CODEC_IDX_AUDIO)
- st->factor = PITCH_SPEED_100;
+ tdspeed_dsp_init(st, (enum dsp_ids)value);
break;
case DSP_FLUSH:
@@ -567,10 +556,8 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
return -1; /* fail the init */
st->this = this;
- st->dsp = dsp;
- this->ip_mask = 0; /* not in-place */
- this->process[0] = tdspeed_process;
- this->process[1] = tdspeed_process_new_format;
+ dsp_proc_set_in_place(dsp, DSP_PROC_TIMESTRETCH, false);
+ this->process = tdspeed_process;
break;
case DSP_PROC_CLOSE:
@@ -580,17 +567,18 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
tdspeed_free_buffers(buffers, NBUFFERS);
break;
+ case DSP_PROC_NEW_FORMAT:
+ retval = tdspeed_new_format(this, dsp, (struct sample_format *)value);
+ break;
+
case TIMESTRETCH_SET_FACTOR:
- /* force update as a format change */
st->samplerate = 0;
st->factor = (int32_t)value;
- st->this->process[0] = tdspeed_process_new_format;
- dsp_proc_activate(st->dsp, DSP_PROC_TIMESTRETCH, true);
+ dsp_proc_want_format_update(dsp, DSP_PROC_TIMESTRETCH);
break;
}
- return 1;
- (void)value;
+ return retval;
}
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,
struct dsp_buffer **buf_p)
{
struct dsp_buffer *buf = *buf_p;
- filter_process((void *)this->data, buf->p32, buf->remcount,
+ filter_process((struct dsp_filter *)this->data, buf->p32, buf->remcount,
buf->format.num_channels);
}
@@ -104,15 +104,17 @@ static intptr_t tone_configure(struct dsp_proc_entry *this,
{
case DSP_PROC_INIT:
if (value != 0)
- break;
+ break; /* Already enabled */
+
this->data = (intptr_t)&tone_filters[dsp_get_id(dsp)];
- this->process[0] = tone_process;
+ this->process = tone_process;
+ /* Fall-through */
case DSP_FLUSH:
filter_flush((struct dsp_filter *)this->data);
break;
}
- return 1;
+ return 0;
}
/* Database entry */