diff options
author | Lennart Poettering <lennart@poettering.net> | 2007-10-01 20:16:28 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2007-10-01 20:16:28 +0000 |
commit | 7d83e5c7816b5e343695a75ba58b32dbe1be969a (patch) | |
tree | bfd1dfc9b7c8f4a2aaf66c1b30e78355dee8c88a /converter.c | |
parent | 762196328ab7e60f1d2908fd5a337d2ca99726dd (diff) |
move all sources down to a seperate src/ tree
git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@34 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce
Diffstat (limited to 'converter.c')
-rw-r--r-- | converter.c | 743 |
1 files changed, 0 insertions, 743 deletions
diff --git a/converter.c b/converter.c deleted file mode 100644 index 3b146ce..0000000 --- a/converter.c +++ /dev/null @@ -1,743 +0,0 @@ -#include <math.h> -#include <string.h> - -#include "speex/speex_resampler.h" - -#include "converter.h" -#include "sydney.h" -#include "macro.h" -#include "common.h" -#include "format.h" -#include "volscale.h" -#include "byteswap.h" -#include "zero.h" -#include "add.h" -#include "bbuffer.h" -#include "continued-fraction.h" -#include "malloc.h" -#include "resample.h" - -/* Steps: byteswap -> convert -> volscale -> remap -> resample -> convert -> byteswap -> interleave */ - -/* Sample formats we know to process natively */ -static int native_pcm_format_process(sa_pcm_format_t f) { - return - f == SA_PCM_FORMAT_U8 || - f == SA_PCM_FORMAT_S16_NE || - f == SA_PCM_FORMAT_S32_NE || - f == SA_PCM_FORMAT_FLOAT32_NE; -} - -/* Sample formats we know to resample natively */ -static int native_pcm_format_resample(sa_pcm_format_t f) { - return - f == SA_PCM_FORMAT_S16_NE || - f == SA_PCM_FORMAT_FLOAT32_NE; -} - -static sa_pcm_format_t byteswap_fix(sa_pcm_format_t f) { - - switch (f) { - case SA_PCM_FORMAT_U8: - case SA_PCM_FORMAT_ULAW: - case SA_PCM_FORMAT_ALAW: - return f; - - case SA_PCM_FORMAT_S16_NE: - case SA_PCM_FORMAT_S16_RE: - return SA_PCM_FORMAT_S16_NE; - - case SA_PCM_FORMAT_S24_NE: - case SA_PCM_FORMAT_S24_RE: - return SA_PCM_FORMAT_S24_NE; - - case SA_PCM_FORMAT_S32_NE: - case SA_PCM_FORMAT_S32_RE: - return SA_PCM_FORMAT_S32_NE; - - case SA_PCM_FORMAT_FLOAT32_NE: - case SA_PCM_FORMAT_FLOAT32_RE: - return SA_PCM_FORMAT_FLOAT32_NE; - - case _SA_PCM_FORMAT_MAX: - ; - } - - sa_assert_not_reached(); -} - -static sa_pcm_format_t get_work_format(sa_pcm_format_t a, sa_pcm_format_t b) { - - switch (a) { - case SA_PCM_FORMAT_U8: - case SA_PCM_FORMAT_ULAW: - case SA_PCM_FORMAT_ALAW: - - switch (b) { - case SA_PCM_FORMAT_U8: - return SA_PCM_FORMAT_U8; - - case SA_PCM_FORMAT_ULAW: - case SA_PCM_FORMAT_ALAW: - case SA_PCM_FORMAT_S16_LE: - case SA_PCM_FORMAT_S16_BE: - return SA_PCM_FORMAT_S16_NE; - - case SA_PCM_FORMAT_S24_LE: - case SA_PCM_FORMAT_S24_BE: - case SA_PCM_FORMAT_S32_LE: - case SA_PCM_FORMAT_S32_BE: - return SA_PCM_FORMAT_S32_NE; - - case SA_PCM_FORMAT_FLOAT32_LE: - case SA_PCM_FORMAT_FLOAT32_BE: - return SA_PCM_FORMAT_FLOAT32_NE; - - case _SA_PCM_FORMAT_MAX: - ; - } - - break; - - case SA_PCM_FORMAT_S16_LE: - case SA_PCM_FORMAT_S16_BE: - - switch (b) { - case SA_PCM_FORMAT_U8: - case SA_PCM_FORMAT_ULAW: - case SA_PCM_FORMAT_ALAW: - case SA_PCM_FORMAT_S16_LE: - case SA_PCM_FORMAT_S16_BE: - return SA_PCM_FORMAT_S16_NE; - - case SA_PCM_FORMAT_S24_LE: - case SA_PCM_FORMAT_S24_BE: - case SA_PCM_FORMAT_S32_LE: - case SA_PCM_FORMAT_S32_BE: - return SA_PCM_FORMAT_S32_NE; - - case SA_PCM_FORMAT_FLOAT32_LE: - case SA_PCM_FORMAT_FLOAT32_BE: - return SA_PCM_FORMAT_FLOAT32_NE; - - case _SA_PCM_FORMAT_MAX: - ; - } - break; - - case SA_PCM_FORMAT_S24_LE: - case SA_PCM_FORMAT_S24_BE: - case SA_PCM_FORMAT_S32_LE: - case SA_PCM_FORMAT_S32_BE: - - switch (b) { - case SA_PCM_FORMAT_U8: - case SA_PCM_FORMAT_ULAW: - case SA_PCM_FORMAT_ALAW: - case SA_PCM_FORMAT_S16_LE: - case SA_PCM_FORMAT_S16_BE: - case SA_PCM_FORMAT_S24_LE: - case SA_PCM_FORMAT_S24_BE: - case SA_PCM_FORMAT_S32_LE: - case SA_PCM_FORMAT_S32_BE: - return SA_PCM_FORMAT_S32_NE; - - case SA_PCM_FORMAT_FLOAT32_LE: - case SA_PCM_FORMAT_FLOAT32_BE: - return SA_PCM_FORMAT_FLOAT32_NE; - - case _SA_PCM_FORMAT_MAX: - ; - } - break; - - case SA_PCM_FORMAT_FLOAT32_LE: - case SA_PCM_FORMAT_FLOAT32_BE: - return SA_PCM_FORMAT_FLOAT32_NE; - - case _SA_PCM_FORMAT_MAX: - ; - } - - sa_assert_not_reached(); -} - -static sa_pcm_format_t fix_work_format_for_resample(sa_pcm_format_t f) { - - switch (f) { - case SA_PCM_FORMAT_U8: - case SA_PCM_FORMAT_S16_NE: - return SA_PCM_FORMAT_S16_NE; - break; - - case SA_PCM_FORMAT_S32_NE: - case SA_PCM_FORMAT_FLOAT32_NE: - return SA_PCM_FORMAT_FLOAT32_NE; - break; - - default: - ; - } - - sa_assert_not_reached(); -} - -int sa_converter_init( - sa_converter_t *c, - const pcm_attrs_t *from, - const pcm_attrs_t *to, - int dynamic_rate_enabled) { - - unsigned u, t; - int resample_required; - - sa_assert(c); - sa_assert(from); - sa_assert(to); - - memset(c, 0, sizeof(*c)); - - c->from_pcm_format = from->format; - c->to_pcm_format = to->format; - - c->from_rate = from->rate; - c->to_rate = to->rate; - - c->from_nchannels = from->nchannels; - c->to_nchannels = to->nchannels; - - if (!(c->channel_map_table = sa_new(int, (from->nchannels+1) * to->nchannels))) - goto fail; - - for (u = 0; u < to->nchannels; u++) { - unsigned k = 0; - - for (t = 0; t < from->nchannels; t++) { - - if (from->channel_map[u] == to->channel_map[t]) { - if (u != t) - c->remap_required = 1; - - c->channel_map_table[u * (from->nchannels+1) + k++] += t; - } - } - - if (k > 1) - c->sum_required = 1; - - c->channel_map_table[k] = (unsigned) -1; - } - - if (c->from_nchannels != c->to_nchannels) - c->remap_required = 1; - - resample_required = - from->rate != to->rate || - dynamic_rate_enabled; - - c->work_pcm_format = get_work_format(from->format, to->format); - if (resample_required) - c->work_pcm_format = fix_work_format_for_resample(c->work_pcm_format); - - sa_assert(native_pcm_format_process(c->work_pcm_format)); - sa_assert(!resample_required || native_pcm_format_resample(c->work_pcm_format)); - - c->from_sample_size = sa_get_pcm_sample_size(c->from_pcm_format); - c->work_sample_size = sa_get_pcm_sample_size(c->work_pcm_format); - c->to_sample_size = sa_get_pcm_sample_size(c->to_pcm_format); - - /* Get function pointers */ - c->pre_byteswap_func = sa_get_byteswap_func(from->format); - - if (byteswap_fix(from->format) != c->work_pcm_format) { - c->pre_format_func = sa_get_format_func(byteswap_fix(from->format), c->work_pcm_format); - sa_assert(c->pre_format_func); - } - - c->volscale_func = sa_get_volscale_func(c->work_pcm_format); - sa_assert(c->volscale_func); - - c->zero_func = sa_get_zero_func(c->work_pcm_format); - sa_assert(c->zero_func); - - c->add_func = sa_get_add_func(c->work_pcm_format); - sa_assert(c->add_func); - - if (resample_required) { - c->resample_func = sa_get_resample_func(c->work_pcm_format); - sa_assert(c->resample_func); - } - - if (c->work_pcm_format != byteswap_fix(to->format)) { - c->post_format_func = sa_get_format_func(c->work_pcm_format, byteswap_fix(to->format)); - sa_assert(c->post_format_func); - } - - c->post_byteswap_func = sa_get_byteswap_func(to->format); - - c->interleave_func = sa_get_interleave_func(to->format); - sa_assert(c->interleave_func); - - /* Initialize resampler */ - - if (resample_required) { - if (!(c->speex = speex_resampler_init(c->to_nchannels, c->from_rate, c->to_rate, SPEEX_RESAMPLER_QUALITY_DEFAULT, NULL))) - goto fail; - } - - /* Initialize processing variables */ - - if (!(c->from_process_data = sa_new0(void*, c->from_nchannels))) - goto fail; - - if (!(c->from_stride = sa_new0(size_t, c->from_nchannels))) - goto fail; - - if (!(c->to_process_data = sa_new0(void*, c->to_nchannels))) - goto fail; - - if (!(c->to_stride = sa_new0(size_t, c->to_nchannels))) - goto fail; - - /* Initialize volume stuff */ - if (!(c->volume_factor = sa_new(int32_t, c->from_nchannels))) - goto fail; - - if (!(c->volume_divisor = sa_new(int32_t, c->from_nchannels))) - goto fail; - - c->no_volume = 1; - - /* Initialize bounce buffers */ - - if (sa_bbuffer_init(&c->bb_pre_byteswap, c->from_nchannels, c->from_sample_size) < 0) - goto fail; - if (sa_bbuffer_init(&c->bb_pre_format, c->from_nchannels, c->work_sample_size) < 0) - goto fail; - if (sa_bbuffer_init(&c->bb_volscale, c->from_nchannels, c->work_sample_size) < 0) - goto fail; - if (sa_bbuffer_init(&c->bb_remap, c->to_nchannels, c->work_sample_size) < 0) - goto fail; - if (sa_bbuffer_init(&c->bb_resample, c->to_nchannels, c->work_sample_size) < 0) - goto fail; - if (sa_bbuffer_init(&c->bb_post_format, c->to_nchannels, c->to_sample_size) < 0) - goto fail; - if (sa_bbuffer_init(&c->bb_post_byteswap, c->to_nchannels, c->to_sample_size) < 0) - goto fail; - if (sa_bbuffer_init(&c->bb_interleave, c->to_nchannels, c->to_sample_size) < 0) - goto fail; - if (sa_bbuffer_init(&c->bb_tmp, 1, 1) < 0) - goto fail; - - return 0; - -fail: - sa_converter_done(c); - - return SA_ERROR_OOM; -} - -void sa_converter_done(sa_converter_t *c) { - sa_assert(c); - - sa_free(c->channel_map_table); - - sa_free(c->from_process_data); - sa_free(c->to_process_data); - sa_free(c->from_stride); - sa_free(c->to_stride); - - sa_bbuffer_done(&c->bb_pre_byteswap); - sa_bbuffer_done(&c->bb_pre_format); - sa_bbuffer_done(&c->bb_volscale); - sa_bbuffer_done(&c->bb_remap); - sa_bbuffer_done(&c->bb_resample); - sa_bbuffer_done(&c->bb_post_format); - sa_bbuffer_done(&c->bb_post_byteswap); - sa_bbuffer_done(&c->bb_interleave); - sa_bbuffer_done(&c->bb_tmp); - - if (c->speex) - speex_resampler_destroy(c->speex); - - sa_free(c->zero_buffer); - - sa_free(c->volume_divisor); - sa_free(c->volume_factor); - memset(c, 0, sizeof(*c)); -} - -void* sa_converter_get_zero_buffer(sa_converter_t *c, size_t size) { - void *b; - - sa_assert(c); - sa_assert(size > 0); - - if (c->zero_buffer && c->zero_size >= size) - return c->zero_buffer; - - sa_free(c->zero_buffer); - - if (!(c->zero_buffer = sa_malloc(size))) - return NULL; - - c->zero_func(b, c->work_sample_size, size); - return c->zero_func; -} - -int sa_converter_go( - sa_converter_t *c, - const void *const src[], const size_t sstr[], int sinterleave, - void **dst[], size_t *dstr[], int dinterleave, - size_t *size) { - - size_t* stride; - void** process_data; - int is_bounce; - int interleave; - unsigned i; - - sa_assert(c); - - is_bounce = 0; - stride = (size_t*) sstr; - process_data = (void**) src; - interleave = !!sinterleave; - dinterleave = !!dinterleave; - - if (c->no_volume && - !c->remap_required && - !c->resample_func && - c->from_pcm_format == c->to_pcm_format) { - - /* We can shortcut this, since we don't need to do any real work.*/ - - goto do_interleave; - } - - if (c->pre_byteswap_func) { - size_t k; - - k = dinterleave ? c->from_sample_size*c->from_nchannels : c->from_sample_size; - - for (i = 0; i < c->from_nchannels; i++) { - void *b; - - if (!(b = sa_bbuffer_get(&c->bb_pre_byteswap, i, *size, dinterleave))) - return SA_ERROR_OOM; - - c->pre_byteswap_func(b, k, process_data[i], stride[i], *size); - c->from_process_data[i] = b; - c->from_stride[i] = k; - } - - process_data = c->from_process_data; - stride = c->from_stride; - interleave = dinterleave; - is_bounce = 1; - } - - if (c->pre_format_func) { - - if (is_bounce && c->from_sample_size == c->to_sample_size) { - - /* The data to process is already in a bounce buffer, we - * can do this in-place */ - - for (i = 0; i < c->from_nchannels; i++) - c->pre_format_func(&c->bb_tmp, process_data[i], stride[i], process_data[i], stride[i], *size); - - } else { - size_t k, new_size; - - new_size = *size / c->from_sample_size * c->work_sample_size; - k = dinterleave ? c->work_sample_size*c->from_nchannels : c->work_sample_size; - - for (i = 0; i < c->from_nchannels; i++) { - void *b; - - if (!(b = sa_bbuffer_get(&c->bb_pre_format, i, new_size, dinterleave))) - return SA_ERROR_OOM; - - c->pre_format_func(&c->bb_tmp, b, k, process_data[i], stride[i], *size); - c->from_process_data[i] = b; - c->from_stride[i] = k; - } - - process_data = c->from_process_data; - stride = c->from_stride; - *size = new_size; - interleave = dinterleave; - is_bounce = 1; - } - } - - if (!c->no_volume) { - - sa_assert(c->volscale_func); - - if (is_bounce) { - - /* The data to process is already in a bounce buffer, we - * can do this in-place */ - - for (i = 0; i < c->from_nchannels; i++); - c->volscale_func(process_data[i], stride[i], process_data[i], stride[i], c->volume_factor[i], c->volume_divisor[i], *size); - - } else { - size_t k; - - k = dinterleave ? c->work_sample_size*c->from_nchannels : c->work_sample_size; - - for (i = 0; i < c->from_nchannels; i++) { - void *b; - - if (!(b = sa_bbuffer_get(&c->bb_volscale, i, *size, dinterleave))) - return SA_ERROR_OOM; - - c->volscale_func(b, k, process_data[i], stride[i], c->volume_factor[i], c->volume_divisor[i], *size); - c->from_process_data[i] = b; - c->from_stride[i] = k; - } - - process_data = c->from_process_data; - stride = c->from_stride; - interleave = dinterleave; - is_bounce = 1; - } - } - - if (c->remap_required) { - size_t k; - int need_proper_interleave = 0; - - k = dinterleave ? c->work_sample_size*c->to_nchannels : c->work_sample_size; - - for (i = 0; i < c->to_nchannels; i++) { - void *b; - int *p = &c->channel_map_table[i * (c->from_nchannels+1)]; - - if (p[0] == -1) { - /* We have to write silence to this channel */ - - if (!(b = sa_converter_get_zero_buffer(c, *size))) - return SA_ERROR_OOM; - - c->to_process_data[i] = b; - c->to_stride[i] = c->work_sample_size; - - need_proper_interleave = 1; - } else if (p[1] == -1) { - /* Just one channel, nothing to mix */ - - c->to_process_data[i] = process_data[p[0]]; - c->to_stride[i] = stride[p[0]]; - - need_proper_interleave = 1; - } else { - int j; - - /* We have to mix two or more channels */ - - if (!(b = sa_bbuffer_get(&c->bb_remap, i, *size, dinterleave))) - return SA_ERROR_OOM; - - c->add_func(b, k, process_data[p[0]], stride[p[0]], process_data[p[1]], stride[p[1]], *size); - - for (j = 2; p[j] != -1; j++) - c->add_func(b, k, b, k, process_data[p[j]], stride[p[j]], *size); - - c->to_process_data[i] = b; - c->to_stride[i] = k; - } - } - - process_data = c->to_process_data; - stride = c->to_stride; - interleave = need_proper_interleave ? -1 : dinterleave; - is_bounce = 1; - } - - if (c->resample_func) { - size_t k; - size_t new_size; - - k = dinterleave ? c->work_sample_size*c->to_nchannels : c->work_sample_size; - - new_size = (size_t) (((((uint64_t) *size+c->work_sample_size-1)/c->work_sample_size)*c->to_rate)/c->from_rate+1)*c->work_sample_size; /* FIXME */ - - for (i = 0; i < c->to_nchannels; i++) { - void *b; - - if (!(b = sa_bbuffer_get(&c->bb_resample, i, new_size, dinterleave))) - return SA_ERROR_OOM; - - c->resample_func(c->speex, i, b, k, process_data[i], stride[i], *size, &new_size); - c->to_process_data[i] = b; - c->to_stride[i] = k; - } - - process_data = c->to_process_data; - stride = c->to_stride; - *size = new_size; - interleave = dinterleave; - is_bounce = 1; - } - - if (c->post_format_func) { - - if (is_bounce && c->work_sample_size == c->to_sample_size) { - - /* The data to process is already in a bounce buffer, we - * can do this in-place */ - - for (i = 0; i < c->to_nchannels; i++) - c->post_format_func(&c->bb_tmp, process_data[i], stride[i], process_data[i], stride[i], *size); - - } else { - size_t k, new_size; - - k = dinterleave ? c->to_sample_size*c->to_nchannels : c->to_sample_size; - new_size = *size / c->work_sample_size * c->to_sample_size; - - for (i = 0; i < c->to_nchannels; i++) { - void *b; - - if (!(b = sa_bbuffer_get(&c->bb_post_format, i, new_size, dinterleave))) - return SA_ERROR_OOM; - - c->post_format_func(&c->bb_tmp, b, k, process_data[i], stride[i], *size); - c->to_process_data[i] = b; - c->to_stride[i] = k; - } - - process_data = c->to_process_data; - stride = c->to_stride; - *size = new_size; - interleave = dinterleave; - is_bounce = 1; - } - } - - if (c->post_byteswap_func) { - - if (is_bounce) { - - /* The data to process is already in a bounce buffer, we - * can do this in-place */ - - for (i = 0; i < c->to_nchannels; i++) - c->post_byteswap_func(process_data[i], stride[i], process_data[i], stride[i], *size); - - } else { - size_t k; - - k = dinterleave ? c->to_sample_size*c->to_nchannels : c->to_sample_size; - - for (i = 0; i < c->to_nchannels; i++) { - void *b; - - if (!(b = sa_bbuffer_get(&c->bb_post_byteswap, i, *size, dinterleave))) - return SA_ERROR_OOM; - - c->post_byteswap_func(b, k, process_data[i], stride[i], *size); - - c->to_process_data[i] = b; - c->to_stride[i] = k; - } - - process_data = c->to_process_data; - stride = c->to_stride; - interleave = dinterleave; - is_bounce = 1; - } - } - -do_interleave: - - if (interleave != dinterleave) { - size_t k; - - k = dinterleave ? c->to_sample_size*c->to_nchannels : c->to_sample_size; - - for (i = 0; i < c->to_nchannels; i++) { - void *b; - - if (!(b = sa_bbuffer_get(&c->bb_interleave, i, *size, dinterleave))) - return SA_ERROR_OOM; - - c->interleave_func(b, k, process_data[i], stride[i], *size); - - c->to_process_data[i] = b; - c->to_stride[i] = k; - } - - process_data = c->to_process_data; - stride = c->to_stride; - interleave = dinterleave; - is_bounce = 1; - } - - *dstr = stride; - *dst = process_data; - - return SA_SUCCESS; -} - -void sa_converter_set_volume(sa_converter_t *c, const int32_t vol[]) { - unsigned i; - int no_volume = 1; - - sa_assert(c); - - for (i = 0; i < c->from_nchannels; i++) { - int num, denom; - - if (vol[i] == 0) { - c->volume_factor[i] = 1; - c->volume_divisor[i] = 1; - } else if (vol[i] <= SA_VOLUME_MUTED) { - c->volume_factor[i] = 0; - c->volume_divisor[i] = 1; - no_volume = 0; - } else { - float f = powf(10.0, (float) vol[i] / 2000); - - sa_continued_fraction(f, 0x7FFF, &num, &denom); - - if (num != 1 || denom != 1) - no_volume = 0; - - c->volume_factor[i] = (int32_t) num; - c->volume_divisor[i] = (int32_t) denom; - } - } - - c->no_volume = no_volume; -} - -int sa_converter_go_interleaved( - sa_converter_t *c, - const void *const data, - void **dst[], size_t *dstr[], int dinterleave, - size_t *size) { - - unsigned i; - const uint8_t *d = data; - unsigned stride = c->from_nchannels * c->from_sample_size; - - for (i = 0; i < c->from_nchannels; i++) { - c->from_process_data[i] = (void*) data; - d += c->from_sample_size; - c->from_stride[i] = stride; - } - - return sa_converter_go(c, (const void *const*) c->from_process_data, c->from_stride, 1, dst, dstr, dinterleave, size); -} - -void sa_converter_set_ratio(sa_converter_t *c, unsigned rate1, unsigned rate2) { - assert(c); - assert(c->speex); - - speex_resampler_set_rate(c->speex, rate1, rate2); -} |