/* Resampling library * Copyright (C) <2001> David A. Schleef <ds@schleef.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <string.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <liboil/liboil.h> #include "resample.h" #include "buffer.h" #include "debug.h" void resample_scale_ref (ResampleState * r); void resample_scale_functable (ResampleState * r); GST_DEBUG_CATEGORY (libaudioresample_debug); void resample_init (void) { static int inited = 0; if (!inited) { oil_init (); inited = 1; GST_DEBUG_CATEGORY_INIT (libaudioresample_debug, "libaudioresample", 0, "audio resampling library"); } } ResampleState * resample_new (void) { ResampleState *r; r = malloc (sizeof (ResampleState)); memset (r, 0, sizeof (ResampleState)); r->filter_length = 16; r->i_start = 0; if (r->filter_length & 1) { r->o_start = 0; } else { r->o_start = r->o_inc * 0.5; } r->queue = audioresample_buffer_queue_new (); r->out_tmp = malloc (10000 * sizeof (double)); r->need_reinit = 1; return r; } void resample_free (ResampleState * r) { if (r->buffer) { free (r->buffer); } if (r->ft) { functable_free (r->ft); } if (r->queue) { audioresample_buffer_queue_free (r->queue); } if (r->out_tmp) { free (r->out_tmp); } free (r); } static void resample_buffer_free (AudioresampleBuffer * buffer, void *priv) { if (buffer->priv2) { ((void (*)(void *)) buffer->priv2) (buffer->priv); } } /* * free_func: a function that frees the given closure. If NULL, caller is * responsible for freeing. */ void resample_add_input_data (ResampleState * r, void *data, int size, void (*free_func) (void *), void *closure) { AudioresampleBuffer *buffer; RESAMPLE_DEBUG ("data %p size %d", data, size); buffer = audioresample_buffer_new_with_data (data, size); buffer->free = resample_buffer_free; buffer->priv2 = (void *) free_func; buffer->priv = closure; audioresample_buffer_queue_push (r->queue, buffer); } void resample_input_flush (ResampleState * r) { RESAMPLE_DEBUG ("flush"); audioresample_buffer_queue_flush (r->queue); r->buffer_filled = 0; r->need_reinit = 1; } void resample_input_pushthrough (ResampleState * r) { AudioresampleBuffer *buffer; int filter_bytes; int buffer_filled; if (r->sample_size == 0) return; filter_bytes = r->filter_length * r->sample_size; buffer_filled = r->buffer_filled; RESAMPLE_DEBUG ("pushthrough filter_bytes %d, filled %d", filter_bytes, buffer_filled); /* if we have no pending samples, we don't need to do anything. */ if (buffer_filled <= 0) return; /* send filter_length/2 number of samples so we can get to the * last queued samples */ buffer = audioresample_buffer_new_and_alloc (filter_bytes / 2); memset (buffer->data, 0, buffer->length); RESAMPLE_DEBUG ("pushthrough %u", buffer->length); audioresample_buffer_queue_push (r->queue, buffer); } void resample_input_eos (ResampleState * r) { RESAMPLE_DEBUG ("EOS"); resample_input_pushthrough (r); r->eos = 1; } int resample_get_output_size_for_input (ResampleState * r, int size) { int outsize; double outd; int avail; int filter_bytes; int buffer_filled; if (r->sample_size == 0) return 0; filter_bytes = r->filter_length * r->sample_size; buffer_filled = filter_bytes / 2 - r->buffer_filled / 2; avail = audioresample_buffer_queue_get_depth (r->queue) + size - buffer_filled; RESAMPLE_DEBUG ("avail %d, o_rate %f, i_rate %f, filter_bytes %d, filled %d", avail, r->o_rate, r->i_rate, filter_bytes, buffer_filled); if (avail <= 0) return 0; outd = (double) avail *r->o_rate / r->i_rate; outsize = (int) floor (outd); /* round off for sample size */ outsize -= outsize % r->sample_size; return outsize; } int resample_get_input_size_for_output (ResampleState * r, int size) { int outsize; double outd; int avail; if (r->sample_size == 0) return 0; avail = size; RESAMPLE_DEBUG ("size %d, o_rate %f, i_rate %f", avail, r->o_rate, r->i_rate); outd = (double) avail *r->i_rate / r->o_rate; outsize = (int) ceil (outd); /* round off for sample size */ outsize -= outsize % r->sample_size; return outsize; } int resample_get_output_size (ResampleState * r) { return resample_get_output_size_for_input (r, 0); } int resample_get_output_data (ResampleState * r, void *data, int size) { r->o_buf = data; r->o_size = size; if (size == 0) return 0; switch (r->method) { case 0: resample_scale_ref (r); break; case 1: resample_scale_functable (r); break; default: break; } return size - r->o_size; } void resample_set_filter_length (ResampleState * r, int length) { r->filter_length = length; r->need_reinit = 1; } void resample_set_input_rate (ResampleState * r, double rate) { r->i_rate = rate; r->need_reinit = 1; } void resample_set_output_rate (ResampleState * r, double rate) { r->o_rate = rate; r->need_reinit = 1; } void resample_set_n_channels (ResampleState * r, int n_channels) { r->n_channels = n_channels; r->sample_size = r->n_channels * resample_format_size (r->format); r->need_reinit = 1; } void resample_set_format (ResampleState * r, ResampleFormat format) { r->format = format; r->sample_size = r->n_channels * resample_format_size (r->format); r->need_reinit = 1; } void resample_set_method (ResampleState * r, int method) { r->method = method; r->need_reinit = 1; } int resample_format_size (ResampleFormat format) { switch (format) { case RESAMPLE_FORMAT_S16: return 2; case RESAMPLE_FORMAT_S32: case RESAMPLE_FORMAT_F32: return 4; case RESAMPLE_FORMAT_F64: return 8; } return 0; }