summaryrefslogtreecommitdiff
path: root/lib/rbcodec
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec')
-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 78e7b8f..2ae2d45 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 22a60e4..bdcc37b 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 3fb51a7..bd8ee95 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 84a23a4..c54bda1 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 0119da8..713190d 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 672212b..a19ef52 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 c534437..902385f 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 284f34c..65d2a11 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 0afe75c..22b7a4a 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 4a8050b..d57d236 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 d58f095..372ef9b 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 34dc35b..20bb78e 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 de852d0..522789f 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 6a495bd..e668c85 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 922c966..01381ea 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 */