/*- * Copyright (c) 2009 Ariff Abdullah * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef SND_USE_FXDIV #define SND_USE_FXDIV #include "snd_fxdiv_gen.h" #endif #define Z_QUALITY_MIN 0 #define Z_QUALITY_MAX 6 #define Z_QUALITY_ZOH Z_QUALITY_MIN #define Z_QUALITY_LINEAR Z_QUALITY_MIN #define Z_QUALITY_SINC 3 #define Z_GRC3_BUFSZ 8192 #define Z_GRC3_MAXCHAN 8 #define Z_MULTIFORMAT 0 #define AFMT_S_NE AFMT_S32_NE struct feeder_grc3_info { uint32_t src; uint32_t dst; uint32_t channels; uint32_t align; uint32_t maxfeed; int quality; grc3state_t grc[Z_GRC3_MAXCHAN]; int32_t buffer[Z_GRC3_BUFSZ]; }; static int feeder_grc3_reset(struct feeder_grc3_info *info) { uint32_t i; info->align = PCM_32_BPS * info->channels; info->maxfeed = SND_FXDIV(sizeof(info->buffer), info->align); for (i = 0; i < info->channels; i++) { grc3_reset(&(info->grc[i])); grc3_setup(&(info->grc[i]), info->src, info->dst); } return (0); } static int feeder_grc3_get(struct pcm_feeder *f, int what) { struct feeder_grc3_info *info; int ret; info = f->data; switch (what) { case FEEDRATE_SRC: ret = info->src; break; case FEEDRATE_DST: ret = info->dst; break; case FEEDRATE_QUALITY: ret = info->quality; break; case FEEDRATE_CHANNELS: ret = info->channels; break; default: return (-1); break; } return (ret); } static int feeder_grc3_set(struct pcm_feeder *f, int what, int32_t value) { struct feeder_grc3_info *info; info = f->data; switch (what) { case FEEDRATE_SRC: if (info->src == (uint32_t)value) return (0); info->src = (uint32_t)value; break; case FEEDRATE_DST: if (info->dst == (uint32_t)value) return (0); info->dst = (uint32_t)value; break; case FEEDRATE_QUALITY: if (value < Z_QUALITY_MIN || value > Z_QUALITY_MAX) return (EINVAL); if (info->quality == value) return (0); info->quality = value; break; case FEEDRATE_CHANNELS: if (value > Z_GRC3_MAXCHAN) return (E2BIG); if (info->channels == (uint32_t)value) return (0); info->channels = (uint32_t)value; break; default: return (EINVAL); break; } return (feeder_grc3_reset(info)); } static int feeder_grc3_init(struct pcm_feeder *f) { struct feeder_grc3_info *info; int error; if (f->desc->in != f->desc->out || AFMT_ENCODING(f->desc->in) != AFMT_S32_NE || AFMT_CHANNEL(f->desc->in) > Z_GRC3_MAXCHAN) return (EINVAL); info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT | M_ZERO); if (info == NULL) return (ENOMEM); info->src = 48000; info->dst = 48000; info->channels = AFMT_CHANNEL(f->desc->in); info->quality = Z_QUALITY_SINC; error = feeder_grc3_reset(info); if (error != 0) { free(info, M_DEVBUF); return (error); } f->data = info; return (error); } static int feeder_grc3_free(struct pcm_feeder *f) { struct feeder_grc3_info *info; info = f->data; if (info != NULL) free(info, M_DEVBUF); return (0); } static int feeder_grc3_feed(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b, uint32_t count, void *source) { struct feeder_grc3_info *info; uint32_t i, osz, isz; info = f->data; osz = SND_FXDIV(count, info->align); isz = ((uint64_t)info->src * osz) / info->dst; if (isz < 1) return (0); if (isz > info->maxfeed) isz = info->maxfeed; isz = SND_FXDIV(FEEDER_FEED(f->source, c, (uint8_t *)info->buffer, isz * info->align, source), info->align); #if 0 /* 32bit -> 24bit */ for (i = 0; i < (isz * info->channels); i++) info->buffer[i] >>= 8; #endif for (i = 0; i < info->channels; i++) grc3_convert(&(info->grc[i]), info->quality, info->buffer, b, isz, osz, info->channels, i); #if 0 /* 24bit -> 32bit */ for (i = 0; i < (info->grc[0].outsz * info->channels); i++) ((int32_t *)b)[i] <<= 8; #endif return (info->grc[0].outsz * info->align); } static struct pcm_feederdesc feeder_rate_desc[] = { { FEEDER_RATE, AFMT_S32_NE, AFMT_S32_NE, 0, 0 }, { 0, 0, 0, 0, 0 }, }; static kobj_method_t feeder_rate_methods[] = { KOBJMETHOD(feeder_init, feeder_grc3_init), KOBJMETHOD(feeder_free, feeder_grc3_free), KOBJMETHOD(feeder_set, feeder_grc3_set), KOBJMETHOD(feeder_get, feeder_grc3_get), KOBJMETHOD(feeder_feed, feeder_grc3_feed), KOBJMETHOD_END }; FEEDER_DECLARE(feeder_rate, NULL);