diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index 4bc51c273..032af578d 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -1630,7 +1630,7 @@ static int parse_prop_params(struct impl *this, struct spa_pod *params) if (changed) { this->props.filter_graph_disabled = filter_graph_disabled; if (this->setup) - channelmix_init(&this->mix); + channelmix_reconfigure(&this->mix); } return changed; } @@ -2322,6 +2322,9 @@ static int setup_channelmix(struct impl *this, uint32_t channels, uint32_t *posi (src_chan != dst_chan || src_mask != dst_mask)) return -EPERM; + if (this->mix.free) + channelmix_free(&this->mix); + this->mix.src_chan = src_chan; this->mix.src_mask = src_mask; this->mix.dst_chan = dst_chan; @@ -4319,6 +4322,8 @@ static int impl_clear(struct spa_handle *handle) free(this->graph_descs[i]); } + if (this->mix.free) + channelmix_free(&this->mix); if (this->resample.free) resample_free(&this->resample); if (this->wav_file != NULL) diff --git a/spa/plugins/audioconvert/channelmix-ops-c.c b/spa/plugins/audioconvert/channelmix-ops-c.c index 2f03df84e..6e0113b5e 100644 --- a/spa/plugins/audioconvert/channelmix-ops-c.c +++ b/spa/plugins/audioconvert/channelmix-ops-c.c @@ -270,9 +270,9 @@ channelmix_f32_2_4_c(struct channelmix *mix, void * SPA_RESTRICT dst[], } else { sub_c(d[2], s[0], s[1], n_samples); - delay_convolve_run_c(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay, + delay_convolve_run_c(mix->buffer[1], &mix->pos[1], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[3], d[2], -v3, n_samples); - delay_convolve_run_c(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay, + delay_convolve_run_c(mix->buffer[0], &mix->pos[0], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[2], d[2], v2, n_samples); } } @@ -338,9 +338,9 @@ channelmix_f32_2_5p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], } else { sub_c(d[4], s[0], s[1], n_samples); - delay_convolve_run_c(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay, + delay_convolve_run_c(mix->buffer[1], &mix->pos[1], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[5], d[4], -v5, n_samples); - delay_convolve_run_c(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay, + delay_convolve_run_c(mix->buffer[0], &mix->pos[0], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[4], d[4], v4, n_samples); } } @@ -374,9 +374,9 @@ channelmix_f32_2_7p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], } else { sub_c(d[6], s[0], s[1], n_samples); - delay_convolve_run_c(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay, + delay_convolve_run_c(mix->buffer[1], &mix->pos[1], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[7], d[6], -v7, n_samples); - delay_convolve_run_c(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay, + delay_convolve_run_c(mix->buffer[0], &mix->pos[0], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[6], d[6], v6, n_samples); } } diff --git a/spa/plugins/audioconvert/channelmix-ops-sse.c b/spa/plugins/audioconvert/channelmix-ops-sse.c index f99fb1f3a..1a34c2bb3 100644 --- a/spa/plugins/audioconvert/channelmix-ops-sse.c +++ b/spa/plugins/audioconvert/channelmix-ops-sse.c @@ -456,9 +456,9 @@ channelmix_f32_2_5p1_sse(struct channelmix *mix, void * SPA_RESTRICT dst[], } else { sub_sse(d[4], s[0], s[1], n_samples); - delay_convolve_run_sse(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay, + delay_convolve_run_sse(mix->buffer[1], &mix->pos[1], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[5], d[4], -v5, n_samples); - delay_convolve_run_sse(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay, + delay_convolve_run_sse(mix->buffer[0], &mix->pos[0], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[4], d[4], v4, n_samples); } } @@ -492,9 +492,9 @@ channelmix_f32_2_7p1_sse(struct channelmix *mix, void * SPA_RESTRICT dst[], } else { sub_sse(d[6], s[0], s[1], n_samples); - delay_convolve_run_sse(mix->buffer[1], &mix->pos[1], BUFFER_SIZE, mix->delay, + delay_convolve_run_sse(mix->buffer[1], &mix->pos[1], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[7], d[6], -v7, n_samples); - delay_convolve_run_sse(mix->buffer[0], &mix->pos[0], BUFFER_SIZE, mix->delay, + delay_convolve_run_sse(mix->buffer[0], &mix->pos[0], mix->buffer_size, mix->delay, mix->taps, mix->n_taps, d[6], d[6], v6, n_samples); } } diff --git a/spa/plugins/audioconvert/channelmix-ops.c b/spa/plugins/audioconvert/channelmix-ops.c index 8ae172fbd..c5f20c26b 100644 --- a/spa/plugins/audioconvert/channelmix-ops.c +++ b/spa/plugins/audioconvert/channelmix-ops.c @@ -15,6 +15,8 @@ #include "channelmix-ops.h" #include "hilbert.h" +#define MAX_BUFFER_SIZE 4096 + #define ANY ((uint32_t)-1) #define EQ ((uint32_t)-2) @@ -192,7 +194,7 @@ static bool match_mix(struct channelmix *mix, return matched; } -static int make_matrix(struct channelmix *mix) +static void impl_channelmix_reconfigure(struct channelmix *mix) { float matrix[MAX_CHANNELS][MAX_CHANNELS] = {{ 0.0f }}; uint64_t src_mask = mix->src_mask, src_paired; @@ -782,7 +784,6 @@ done: for (j = 0; j < src_chan; j++) mix->matrix_orig[i][j] /= maxsum; } - return 0; } static void impl_channelmix_set_volume(struct channelmix *mix, float volume, bool mute, @@ -875,6 +876,8 @@ static void impl_channelmix_set_volume(struct channelmix *mix, float volume, boo static void impl_channelmix_free(struct channelmix *mix) { mix->process = NULL; + free(mix->data); + mix->data = NULL; } void channelmix_reset(struct channelmix *mix) @@ -895,6 +898,9 @@ void channelmix_reset(struct channelmix *mix) int channelmix_init(struct channelmix *mix) { const struct channelmix_info *info; + void *d, *b[2]; + size_t taps_size, buffer_size, alloc_size, dstptr_size, matrow_size, matrix_size, lr4_size; + uint32_t i; if (mix->src_chan > MAX_CHANNELS || mix->dst_chan > MAX_CHANNELS) @@ -908,29 +914,62 @@ int channelmix_init(struct channelmix *mix) mix->free = impl_channelmix_free; mix->process = info->process; mix->set_volume = impl_channelmix_set_volume; + mix->reconfigure = impl_channelmix_reconfigure; mix->delay = (uint32_t)(mix->rear_delay * mix->freq / 1000.0f); mix->func_cpu_flags = info->cpu_flags; mix->func_name = info->name; - spa_zero(mix->taps_mem); - mix->taps = SPA_PTR_ALIGN(mix->taps_mem, CHANNELMIX_OPS_MAX_ALIGN, float); - mix->buffer[0] = SPA_PTR_ALIGN(&mix->buffer_mem[0], CHANNELMIX_OPS_MAX_ALIGN, float); - mix->buffer[1] = SPA_PTR_ALIGN(&mix->buffer_mem[2*BUFFER_SIZE], CHANNELMIX_OPS_MAX_ALIGN, float); + if (mix->hilbert_taps > 0) + mix->n_taps = SPA_CLAMP(mix->hilbert_taps, 15u, MAX_TAPS) | 1; + else + mix->n_taps = 1; + + mix->buffer_size = mix->delay + mix->n_taps; + if (mix->buffer_size > MAX_BUFFER_SIZE) { + mix->buffer_size = MAX_BUFFER_SIZE; + mix->delay = MAX_BUFFER_SIZE - mix->n_taps; + } + + taps_size = SPA_ROUND_UP(mix->n_taps * sizeof(float), CHANNELMIX_OPS_MAX_ALIGN); + buffer_size = SPA_ROUND_UP(mix->buffer_size*2 * sizeof(float), CHANNELMIX_OPS_MAX_ALIGN); + dstptr_size = SPA_ROUND_UP(mix->dst_chan * sizeof(void*), CHANNELMIX_OPS_MAX_ALIGN); + matrow_size = SPA_ROUND_UP(mix->src_chan * sizeof(float), CHANNELMIX_OPS_MAX_ALIGN); + matrix_size = SPA_ROUND_UP(mix->dst_chan * matrow_size, CHANNELMIX_OPS_MAX_ALIGN); + lr4_size = SPA_ROUND_UP(mix->dst_chan * sizeof(struct lr4), CHANNELMIX_OPS_MAX_ALIGN); + + alloc_size = taps_size + buffer_size*2 + dstptr_size*2 + lr4_size + matrix_size*2 + CHANNELMIX_OPS_MAX_ALIGN; + d = calloc(1, alloc_size); + if (d == NULL) + return -errno; + + mix->data = d; + mix->taps = SPA_PTR_ALIGN(d, CHANNELMIX_OPS_MAX_ALIGN, float); + mix->buffer[0] = SPA_PTROFF_ALIGN(mix->taps, taps_size, CHANNELMIX_OPS_MAX_ALIGN, float); + mix->buffer[1] = SPA_PTROFF_ALIGN(mix->buffer[0], buffer_size, CHANNELMIX_OPS_MAX_ALIGN, float); + mix->matrix = SPA_PTROFF_ALIGN(mix->buffer[1], buffer_size, CHANNELMIX_OPS_MAX_ALIGN, float*); + mix->matrix_orig = SPA_PTROFF_ALIGN(mix->matrix, dstptr_size, CHANNELMIX_OPS_MAX_ALIGN, float*); + mix->lr4 = SPA_PTROFF_ALIGN(mix->matrix_orig, dstptr_size, CHANNELMIX_OPS_MAX_ALIGN, struct lr4); + + b[0] = SPA_PTROFF_ALIGN(mix->lr4, lr4_size, CHANNELMIX_OPS_MAX_ALIGN, float); + b[1] = SPA_PTROFF_ALIGN(b[0], matrix_size, CHANNELMIX_OPS_MAX_ALIGN, float); + + for (i = 0; i < mix->dst_chan; i++) { + mix->matrix[i] = SPA_PTROFF_ALIGN(b[0], matrow_size * i, CHANNELMIX_OPS_MAX_ALIGN, float); + mix->matrix_orig[i] = SPA_PTROFF_ALIGN(b[1], matrow_size * i, CHANNELMIX_OPS_MAX_ALIGN, float); + } if (mix->hilbert_taps > 0) { - mix->n_taps = SPA_CLAMP(mix->hilbert_taps, 15u, MAX_TAPS) | 1; blackman_window(mix->taps, mix->n_taps); hilbert_generate(mix->taps, mix->n_taps); reverse_taps(mix->taps, mix->n_taps); } else { - mix->n_taps = 1; mix->taps[0] = 1.0f; } - if (mix->delay + mix->n_taps > BUFFER_SIZE) - mix->delay = BUFFER_SIZE - mix->n_taps; spa_log_debug(mix->log, "selected %s delay:%d options:%08x", info->name, mix->delay, mix->options); - return make_matrix(mix); + channelmix_reconfigure(mix); + + return 0; } diff --git a/spa/plugins/audioconvert/channelmix-ops.h b/spa/plugins/audioconvert/channelmix-ops.h index f18e76153..cdf828643 100644 --- a/spa/plugins/audioconvert/channelmix-ops.h +++ b/spa/plugins/audioconvert/channelmix-ops.h @@ -22,7 +22,6 @@ #define MASK_5_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR) #define MASK_7_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR) -#define BUFFER_SIZE 4096 #define MAX_TAPS 255u #define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS @@ -63,8 +62,8 @@ struct channelmix { #define CHANNELMIX_FLAG_EQUAL (1<<2) /**< all values are equal */ #define CHANNELMIX_FLAG_COPY (1<<3) /**< 1 on diagonal, can be nxm */ uint32_t flags; - float matrix_orig[MAX_CHANNELS][MAX_CHANNELS]; - float matrix[MAX_CHANNELS][MAX_CHANNELS]; + float **matrix_orig; + float **matrix; float freq; /* sample frequency */ float lfe_cutoff; /* in Hz, 0 is disabled */ @@ -75,13 +74,12 @@ struct channelmix { float lfe_level; /* lfe down/upmix level, 1/2 */ float surround_level; /* surround down/upmix level, sqrt(1/2) */ uint32_t hilbert_taps; /* to phase shift, 0 disabled */ - struct lr4 lr4[MAX_CHANNELS]; + struct lr4 *lr4; - float buffer_mem[2 * BUFFER_SIZE*2 + CHANNELMIX_OPS_MAX_ALIGN/4]; float *buffer[2]; + uint32_t buffer_size; uint32_t pos[2]; uint32_t delay; - float taps_mem[MAX_TAPS + CHANNELMIX_OPS_MAX_ALIGN/4]; float *taps; uint32_t n_taps; @@ -89,6 +87,7 @@ struct channelmix { const void * SPA_RESTRICT src[], uint32_t n_samples); void (*set_volume) (struct channelmix *mix, float volume, bool mute, uint32_t n_channel_volumes, float *channel_volumes); + void (*reconfigure) (struct channelmix *mix); void (*free) (struct channelmix *mix); void *data; @@ -118,6 +117,7 @@ static inline uint32_t channelmix_upmix_from_label(const char *label) #define channelmix_process(mix,...) (mix)->process(mix, __VA_ARGS__) #define channelmix_set_volume(mix,...) (mix)->set_volume(mix, __VA_ARGS__) +#define channelmix_reconfigure(mix) (mix)->reconfigure(mix) #define channelmix_free(mix) (mix)->free(mix) #define DEFINE_FUNCTION(name,arch) \