/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (C) 4Front Technologies 1996-2008.
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Purpose: GRC3 Sample Rate Converter
*
* GRC library version 3.1
*/
#include <sys/types.h>
#include "audio_grc3.h"
extern const int32_t filter_data_L[];
extern const int32_t filter_data_M[];
extern const int32_t filter_data_H[];
extern const int32_t filter_data_P[];
#define filter_data_HX filter_data_H
#define filter_data_PX filter_data_P
static int32_t
_muldivu64(uint32_t a, uint32_t val1, uint32_t val2)
{
uint64_t v = ((uint64_t)a) * val1 / val2;
return ((uint32_t)(v));
}
static int32_t
_grc_sat6(int32_t a, int32_t b)
{
int64_t v = ((int64_t)a) * b + (1 << 5);
return ((int32_t)(v >> 6));
}
static int32_t
_grc_sat31(int32_t a, int32_t b)
{
int64_t v = ((int64_t)a) * b + (1 << 30);
return ((int32_t)(v >> 31));
}
#define DEFINE_FILTER(T) \
static int32_t \
_filt31_##T(int32_t a, int32_t idx) \
{ \
int64_t v = ((int64_t)a) * filter_data_##T[idx >> 15]; \
return ((int32_t)(v >> 31)); \
}
#define DEFINE_FILTER_HQ(T) \
static int32_t \
_filt31_##T(int32_t a, int32_t idx) \
{ \
int32_t idx2 = idx>>15; \
int64_t v = ((int64_t)a) * \
\
(filter_data_##T[idx2] + \
(((int64_t)(idx & 32767)) * (filter_data_##T[idx2 + 1] - \
filter_data_##T[idx2]) >> 15)); \
return ((int32_t)(v>>31)); \
}
DEFINE_FILTER(L)
DEFINE_FILTER(M)
DEFINE_FILTER(H)
DEFINE_FILTER_HQ(HX)
DEFINE_FILTER(P)
DEFINE_FILTER_HQ(PX)
#define DEFINE_CONVD(T, SZ) \
static int32_t \
_conv31d_##T(int32_t *history, uint32_t filter, uint32_t incv) \
{ \
int32_t accum = 0; \
\
filter = (1024 << 15) - filter; \
\
while (filter < ((uint32_t)(SZ << 15))) { \
accum += _filt31_##T(*history, filter); \
filter += incv; \
history--; \
} \
\
return (accum); \
}
DEFINE_CONVD(L, 4096)
DEFINE_CONVD(M, 8192)
DEFINE_CONVD(H, 16384)
DEFINE_CONVD(HX, 16384)
DEFINE_CONVD(P, 32768)
DEFINE_CONVD(PX, 32768)
static int32_t
_conv31_L(int32_t *history, uint32_t filter)
{
int32_t accum = 0;
#define ITERATION(p) \
accum += _filt31_##p(*history, filter); \
filter += (1024 << 15); \
history--
ITERATION(L); ITERATION(L); ITERATION(L); ITERATION(L);
return (accum);
}
static int32_t
_conv31_M(int32_t *history, uint32_t filter)
{
int32_t accum = 0;
ITERATION(M); ITERATION(M); ITERATION(M); ITERATION(M);
ITERATION(M); ITERATION(M); ITERATION(M); ITERATION(M);
return (accum);
}
static int32_t
_conv31_H(int32_t *history, uint32_t filter)
{
int32_t accum = 0;
ITERATION(H); ITERATION(H); ITERATION(H); ITERATION(H);
ITERATION(H); ITERATION(H); ITERATION(H); ITERATION(H);
ITERATION(H); ITERATION(H); ITERATION(H); ITERATION(H);
ITERATION(H); ITERATION(H); ITERATION(H); ITERATION(H);
return (accum);
}
static int32_t
_conv31_HX(int32_t *history, uint32_t filter)
{
int32_t accum = 0;
ITERATION(HX); ITERATION(HX); ITERATION(HX); ITERATION(HX);
ITERATION(HX); ITERATION(HX); ITERATION(HX); ITERATION(HX);
ITERATION(HX); ITERATION(HX); ITERATION(HX); ITERATION(HX);
ITERATION(HX); ITERATION(HX); ITERATION(HX); ITERATION(HX);
return (accum);
}
static int32_t
_conv31_P(int32_t *history, uint32_t filter)
{
int32_t accum = 0;
ITERATION(P); ITERATION(P); ITERATION(P); ITERATION(P);
ITERATION(P); ITERATION(P); ITERATION(P); ITERATION(P);
ITERATION(P); ITERATION(P); ITERATION(P); ITERATION(P);
ITERATION(P); ITERATION(P); ITERATION(P); ITERATION(P);
ITERATION(P); ITERATION(P); ITERATION(P); ITERATION(P);
ITERATION(P); ITERATION(P); ITERATION(P); ITERATION(P);
ITERATION(P); ITERATION(P); ITERATION(P); ITERATION(P);
ITERATION(P); ITERATION(P); ITERATION(P); ITERATION(P);
return (accum);
}
static int32_t
_conv31_PX(int32_t *history, uint32_t filter)
{
int32_t accum = 0;
ITERATION(PX); ITERATION(PX); ITERATION(PX); ITERATION(PX);
ITERATION(PX); ITERATION(PX); ITERATION(PX); ITERATION(PX);
ITERATION(PX); ITERATION(PX); ITERATION(PX); ITERATION(PX);
ITERATION(PX); ITERATION(PX); ITERATION(PX); ITERATION(PX);
ITERATION(PX); ITERATION(PX); ITERATION(PX); ITERATION(PX);
ITERATION(PX); ITERATION(PX); ITERATION(PX); ITERATION(PX);
ITERATION(PX); ITERATION(PX); ITERATION(PX); ITERATION(PX);
ITERATION(PX); ITERATION(PX); ITERATION(PX); ITERATION(PX);
return (accum);
}
#define GRC3_RESAMPLE(QUAL) \
static void \
grc3_upsample_##QUAL(grc3state_t *grc, const int32_t *src, \
int32_t *dst, uint32_t sz, uint32_t bufsz, int inc, int offset) \
{ \
int32_t ptr = grc->ptr; \
int32_t srcrate = grc->srcrate; \
int32_t dstrate = grc->dstrate; \
int32_t *history = grc->historyptr; \
int32_t filtfactor = grc->filtfactor; \
uint32_t dstsz = 0; \
\
src += offset; \
dst += offset; \
\
while (sz > 0) { \
while (ptr < dstrate) { \
if (dstsz >= bufsz) \
goto endloop; \
dst[0] = (_conv31_##QUAL(history, \
_grc_sat6(ptr, filtfactor))); \
ptr += srcrate; \
dst += inc; \
dstsz++; \
} \
\
history++; \
if (history >= (grc->history + GRC3_MAXHISTORY * 2)) \
history -= GRC3_MAXHISTORY; \
\
history[0] = history[-GRC3_MAXHISTORY] = (*src); \
\
ptr -= dstrate; \
\
sz--; \
src += inc; \
} \
endloop: \
\
grc->ptr = ptr; \
grc->historyptr = history; \
grc->outsz = dstsz; \
} \
\
static void \
grc3_dnsample_##QUAL(grc3state_t *grc, const int32_t *src, \
int32_t *dst, uint32_t sz, uint32_t bufsz, int inc, int offset) \
{ \
int32_t ptr = grc->ptr; \
int32_t srcrate = grc->srcrate; \
int32_t dstrate = grc->dstrate; \
int32_t sat = grc->sat; \
int32_t *history = grc->historyptr; \
int32_t filtfactor = grc->filtfactor; \
uint32_t dstsz = 0; \
\
src += offset; \
dst += offset; \
\
while (sz > 0) { \
while (ptr >= srcrate) { \
if (dstsz >= bufsz) \
goto endloop; \
ptr -= srcrate; \
dst[0] = (_conv31d_##QUAL(history, \
_grc_sat6(ptr, filtfactor), \
grc->ptr_incv)); \
dst += inc; \
dstsz++; \
} \
\
history++; \
if (history >= (grc->history + GRC3_MAXHISTORY * 2)) \
history -= GRC3_MAXHISTORY; \
\
/* \
* TODO: for better quality multiplier is worth moving \
* to output cascade \
*/ \
history[0] = history[-GRC3_MAXHISTORY] = \
_grc_sat31((*src), sat); \
\
ptr += dstrate; \
\
sz--; \
src += inc; \
} \
endloop: \
\
grc->ptr = ptr; \
grc->historyptr = history; \
grc->outsz = dstsz; \
} \
\
static void \
grc3_resample_##QUAL(grc3state_t *grc, const void *src, void *dst, \
uint32_t sz, uint32_t bufsz, int inc, int offset) \
{ \
if (grc->srcrate <= grc->dstrate) \
grc3_upsample_##QUAL(grc, src, dst, sz, \
bufsz, inc, offset); \
else \
grc3_dnsample_##QUAL(grc, src, dst, sz, \
bufsz, inc, offset); \
}
GRC3_RESAMPLE(L)
GRC3_RESAMPLE(M)
GRC3_RESAMPLE(H)
GRC3_RESAMPLE(HX)
GRC3_RESAMPLE(P)
GRC3_RESAMPLE(PX)
/*
* For performance reasons, we only support 24-bit SRC.
*/
void
grc3_convert(grc3state_t *grc, int quality, const void *src,
void *dst, int sz, int bufsz, int inc, int offset)
{
switch (quality) {
default:
case 0:
case 1:
grc3_resample_L(grc, src, dst, sz, bufsz, inc, offset);
break;
case 2:
grc3_resample_M(grc, src, dst, sz, bufsz, inc, offset);
break;
case 3:
grc3_resample_H(grc, src, dst, sz, bufsz, inc, offset);
break;
case 4:
grc3_resample_HX(grc, src, dst, sz, bufsz, inc, offset);
break;
case 5:
grc3_resample_P(grc, src, dst, sz, bufsz, inc, offset);
break;
case 6:
grc3_resample_PX(grc, src, dst, sz, bufsz, inc, offset);
break;
}
}
void
grc3_reset(grc3state_t *grc)
{
int32_t t;
grc->ptr = 0;
grc->historyptr = grc->history + GRC3_MAXHISTORY;
for (t = 0; t < GRC3_MAXHISTORY * 2; t++)
grc->history[t] = 0;
}
static void
grc3_setup_up(grc3state_t *grc, uint32_t fromRate, uint32_t toRate)
{
grc->srcrate = fromRate;
grc->dstrate = toRate;
grc->filtfactor = 0x80000000U / toRate;
}
static void
grc3_setup_dn(grc3state_t *grc, uint32_t fromRate, uint32_t toRate)
{
grc->srcrate = fromRate;
grc->dstrate = toRate;
grc->filtfactor = 0x80000000U / fromRate;
grc->ptr_incv = _muldivu64(1024 << 15, toRate, fromRate);
grc->sat = _muldivu64(0x80000000U, toRate, fromRate);
}
void
grc3_setup(grc3state_t *grc, uint32_t fromRate, uint32_t toRate)
{
while ((!(fromRate & 1)) && (!(toRate & 1)) && (fromRate > 0)) {
fromRate >>= 1;
toRate >>= 1;
}
if (fromRate <= toRate)
grc3_setup_up(grc, fromRate, toRate);
else
grc3_setup_dn(grc, fromRate, toRate);
}