#include "sydney.h" #define MAX_OPERATIONS 10 typedef struct buffer_spec buffer_spec_t; struct buffer_spec { void *data; size_t size; size_t max_size; }; typedef struct operation operation_t; typedef void (*operation_execute_t)(operation_t *o, buffer_spec_t *source); struct operation { operation_execute_t execute; struct buffer_spec result; size_t sample unsigned nchannels; }; typedef struct pipeline pipeline_t; struct pipeline { operation_t operations[MAX_OPERATIONS]; }; static int native_pcm_format(pcm_format_t f) { /* Sample formats we know to handle natively */ return f == SA_PCM_FORMAT_S16_NE || f == SA_PCM_FORMAT_S32_NE || f == SA_PCM_FORMAT_FLOAT32_NE; } /* Steps: prefmt -> volume -> remap -> resample -> postfmt */ int build_pipeline_output( sa_device_t *dev, sa_pipeline_t *pipeline, sa_pcm_format format, unsigned rate, unsigned nchannels, const sa_channel_t map[]) { int *channel_map_table; unsigned u, t; int prefmt_required; int sum_required = 0; int o = 0; pcm_format_t work_format; operation_execute_t func; sa_assert(dev); sa_assert(pipeline); if (!(channel_map_table = sa_new(int, nchannels * dev->nchannels))) return SA_ERROR_OOM; for (u = 0; u < nchannels; u++) { unsigned k = 0; for (t = 0; t < dev->nchannels; t++) { if (map[u] == map[t]) channel_map_table[u * dev->nchannels + k++] += t; } if (k > 1) sum_required = 1; channel_map_table[k] = (unsigned) -1; } prefmt_required = sum_required || dev->output_volume != 0 || dev->rate != rate || dev->dsr_enabled; if (native_pcm_format(dev->pcm_format)) prefmt_required = 0; if (prefmt_required) { switch (dev->pcm_format) { 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: work_format = SA_PCM_FORMAT_S16_NE; 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: work_format = SA_PCM_FORMAT_S32_NE; break; case SA_PCM_FORMAT_FLOAT32_LE: case SA_PCM_FORMAT_FLOAT32_BE: work_format = SA_PCM_FORMAT_FLOAT32_NE; break; } sa_assert(native_pcm_format(work_format)); func = get_format_converter(dev->pcm_format, work_format); pipeline.operations[o].execute = func; pipeline.operations[o].buffer.data = NULL; pipeline.operations[o].buffer.stride = dev->nchannels * get_sample_size(dev->work_format); pipeline.operations[o]. o++; } else work_format = dev->pcm_format; if (dev->output_volume != 0) { pipeline.operations[o].execute = get_scaler(work_format); pipeline.operations[o].buffer.data = NULL; o++; } if (dev->rate != rate || dev->dsr_enabled) { pipeline.operations[o].execute = get_resampler(work_format); pipeline.operations[o].buffer.data = NULL; o++; } if (work_format != pcm_format) { pipeline.operations[o].execute = get_format_converter(work_format, pcm_format); pipeline.operations[o].buffer.data = NULL; o++; } pipeline.operations[o].execute = NULL; } void execute_pipeline(sa_device_t *dev, pipeline_t *pipeline, const buffer_spec_t *buffer, buffer_spec_t *output) { sa_operation_t *o; sa_assert(dev); sa_assert(pipeline); sa_assert(buffer); for (o = pipeline->operations; o->execute; o++) { o->execute(o, buffer); buffer = &o->buffer; } *output = *buffer; }