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) + { + state->vcl = state->vcr = state->vdiff = 0; + } + else { memset(state->history, 0, sizeof (state->history) + sizeof (state->delay)); state->index = state->delay; } - else - { - state->vcl = state->vcr = state->vdiff = 0; - } } /** 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(, 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; +} + +/* 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) +{ + struct dsp_proc_slot *s = find_proc_slot(dsp, id); + + if (s) + s->version = 0; /* Set invalid */ +} + +/* Set or unset in-place operation */ +void dsp_proc_set_in_place(struct dsp_config *dsp, enum dsp_proc_ids id, + bool in_place) +{ + 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 FORCE_INLINE bool dsp_proc_should_call(struct dsp_proc_entry *this, - struct dsp_buffer *buf, - unsigned int fmt) +static NO_INLINE bool dsp_proc_new_format(struct dsp_proc_slot *s, + struct dsp_config *dsp, + struct dsp_buffer *buf) { - uint32_t ip_mask = this->ip_mask; + struct dsp_proc_entry *this = &s->proc_entry; + struct sample_format *format = &buf->format; - 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)); + switch (proc_db_entry(s)->configure( + this, dsp, DSP_PROC_NEW_FORMAT, (intptr_t)format)) + { + case PROC_NEW_FORMAT_OK: + s->version = format->version; + return true; + + case PROC_NEW_FORMAT_TRANSITION: + return true; + + case PROC_NEW_FORMAT_DEACTIVATED: + s->version = format->version; + return false; + + default: + return false; + } } -/* 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) +static FORCE_INLINE void dsp_proc_call(struct dsp_proc_slot *s, + struct dsp_config *dsp, + struct dsp_buffer **buf_p) { - if (dsp_proc_should_call(this, *buf_p, fmt)) + struct dsp_buffer *buf = *buf_p; + + if (UNLIKELY(buf->format.version != s->version)) { - this->process[fmt == (0u-1u) ? 0 : fmt](this, buf_p); - return true; + if (!dsp_proc_new_format(s, dsp, buf)) + return; } - return false; -} + if (s->mask) + { + if ((s->mask & (buf->proc_mask | NACT_BIT)) || buf->remcount <= 0) + return; -#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 */ + 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; + + if (UNLIKELY(buf->format.version != dsp->io_data.sample_buf.format.version)) + dsp_sample_input_format_change(&dsp->io_data, &buf->format); /* Convert input samples to internal format */ - dsp->io_data.input_samples[fmt](&dsp->io_data, &buf); - fmt = buf->format.changed; - - struct dsp_proc_slot *s = dsp->proc_slots[fmt]; + 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 -#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; + if (this->sample_buf.remcount > 0) + return; - /* Ack configured format change */ - format_change_ack(&this->format); + DSP_PRINT_FORMAT(DSP Input, this->format); - if (dst->remcount > 0) - { - *buf_p = dst; - return; /* data still remains */ - } - - DSP_PRINT_FORMAT(DSP Input, -1, src->format); - - /* 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]; - - this->input_samples[0](this, buf_p); - - if (*buf_p == dst) /* buffer switch? */ - format_change_ack(&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]; } -static void dsp_sample_input_init(struct sample_io_data *this, - enum dsp_ids dsp_id) +/* increment the format version counter */ +static void format_change_set(struct sample_io_data *this) +{ + if (this->format_dirty) + return; + + this->format.version = (uint8_t)(this->format.version + 1) ?: 1; + this->format_dirty = 1; +} + +/* discard the sample buffer */ +static void dsp_sample_input_flush(struct sample_io_data *this) +{ + this->sample_buf.remcount = 0; +} + +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 @@ -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; + dst->format = *format; + dst->format.frequency = NATIVE_FREQUENCY; + dst->format.codec_frequency = NATIVE_FREQUENCY; - if (!active) - { - DEBUGF(" DSP_PROC_RESAMPLE- not active\n"); - dst->format = f; /* Keep track */ - return; /* No resampling required */ - } + if (active) + return PROC_NEW_FORMAT_OK; - format_change_ack(&src->format); - - if (EQU_SAMPLE_FORMAT(f, dst->format)) - { - DEBUGF(" DSP_PROC_RESAMPLE- same dst format\n"); - format_change_ack(&f); /* Nothing changed that matters downstream */ - } - - 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 */