am_src2.c revision 39b361b2ebefcef5612a54ae5cbd2179e19be296
/*
* 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
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Audio Mixer Sample Rate Conversion Routine 2
*
* This module is used by the audio mixer to perform sample rate conversion
* of audio streams. The audio driver actually specifies which sample rate
* conversion routine it wants to use, and then passes that information to
* the audio mixer.
*
* modules being loaded 1st.
*
* NOTE: We do NOT allocate the buffers used for sample rate conversion.
* That is the job of the audio mixer.
*/
/*
* Local sample rate conversion routines.
*/
static int am_src2_adjust(srchdl_t, int, int);
static int *am_src2_convert(srchdl_t, int, int, int *, int *, int *, int *);
static void am_src2_exit(srchdl_t, int);
void *, int);
static int am_src2_up_s(am_src2_data_t *, int *, int *, int);
static int am_src2_up_m(am_src2_data_t *, int *, int *, int);
static int am_src2_dn_s(am_src2_data_t *, int *, int *, int);
static int am_src2_dn_m(am_src2_data_t *, int *, int *, int);
/*
* Global variable to provide generic sample rate conversion facility.
*/
};
/*
* Module Linkage Structures
*/
/* Linkage structure for loadable drivers */
static struct modlmisc amsrc2_modlmisc = {
&mod_miscops, /* drv_modops */
AM_SRC2_MOD_NAME, /* drv_linkinfo */
};
static struct modlinkage amsrc2_modlinkage =
{
MODREV_1, /* ml_rev */
(void*)&amsrc2_modlmisc, /* ml_linkage */
NULL /* NULL terminates the list */
};
/*
* Loadable Module Configuration Entry Points
*
*
* _init()
*
* Description:
* Driver initialization, called when driver is first loaded.
*
* Arguments:
* None
*
* Returns:
* mod_install() status, see mod_install(9f)
*/
int
_init(void)
{
int error;
ATRACE("in amsrc2 _init()", 0);
/* Standard linkage call */
return (error);
}
ATRACE("amsrc2 _init() successful", 0);
return (error);
} /* _init() */
/*
* _fini()
*
* Description
* Module de-initialization, called when driver is to be unloaded.
*
* Arguments:
* None
*
* Returns:
* mod_remove() status, see mod_remove(9f)
*/
int
_fini(void)
{
int error;
ATRACE("in amsrc2 _fini()", 0);
return (error);
}
return (error);
} /* _fini() */
/*
* _info()
*
* Description:
* Module information, returns information about the driver.
*
* Arguments:
* modinfo *modinfop Pointer to an opaque modinfo structure
*
* Returns:
* mod_info() status, see mod_info(9f)
*/
int
{
int rc;
return (rc);
} /* _info() */
/*
* am_src2_adjust()
*
* Description:
* This routine is used to adjust the number of hardware samples so we
* know how many channel samples were converted.
*
* Arguments:
* int dir Direction, AUDIO_PLAY or AUDIO_RECORD
* int samples The number of hardware samples
*
* Returns:
* >= 0 The number of channel samples
* AUDIO_FAILURE Couldn't adjust the size
*/
static int
{
int value;
/* Get the conversion info */
return (AUDIO_FAILURE);
}
/* Do the math */
return (value);
} /* am_src2_adjust() */
/*
* am_src2_convert()
*
* Description:
* This routine manages the sample rate conversion process. It converts
* from src2_inFs to src2_outFs. The input stream must be 16-bit Linear
* PCM held as 32-bit integers.
*
* The returned pointer, if valid, must be one of the two passed in
* pointers. Otherwise memory will become lost.
*
* Arguments:
* int channels The number of channels in conversion
* int dir Direction, AUDIO_PLAY or AUDIO_RECORD
* int *src Original data to convert
* int *ptr1 Conversion buffer
* int *ptr2 Conversion buffer (not used)
* int *samples Pointer to the number of samples to
* convert, and when we return, the number
* of samples converted.
*
* Returns:
* valid pointer Pointer to the converted audio stream
* NULL Conversion failed
*/
/*ARGSUSED*/
static int *
{
int converted;
/* Get the sample rate conversion data */
return (NULL);
}
/* Set conversion function depending on direction and channels */
if (dir == AUDIO_PLAY) {
if (channels == AUDIO_CHANNELS_MONO) {
} else {
}
} else {
if (channels == AUDIO_CHANNELS_MONO) {
} else {
}
}
/* Resample */
return (ptr1);
} /* am_src2_convert() */
/*
* am_src2_exit()
*
* Description:
* Free the private data structure allocated in am_src2_init()
*
* NOTE: We do NOT free the buffers used for sample rate conversion.
*
* Arguments:
* int dir Direction, AUDIO_PLAY or AUDIO_RECORD
*
* Returns:
* void
*/
static void
{
/* Get pointers, based on which direction we are going */
return;
}
/* Get the mutex */
/* Free memory for table pointers */
if (dir == AUDIO_PLAY) {
}
/* Release and destroy the mutex */
} /* am_src2_exit() */
/*
* am_src2_init()
*
* Description:
* Allocate memory for the sample rate conversion private data
* structure and initialize the mutex that guarantees we don't
* mess with buffers and parameters in the middle of a conversion.
* Because the current output sample depends on the current and
* past input samples we require room to store past input samples.
* Here we return the amount of extra room required in bytes.
* We initialise all we can at this point in order to keep the
* work required of am_src2_update() to a minimum.
*
* CAUTION: This routine may be called only once without calling
* am_src2_exit(), otherwise we'll have a memory leak.
*
* Arguments:
* int dir Direction, AUDIO_PLAY or AUDIO_RECORD
*
* Returns:
* size_t prebuffer Prebuffer memory requirement
*/
static size_t
{
int i;
/* Allocate src data structure */
/* Set up mutex */
/* Get the mutex */
if (dir == AUDIO_PLAY) {
/* Scale for 32-bit ints */
pdata->src2_delta_c = 0;
pdata->src2_cover = 0;
for (i = 0; i < AM_SRC2_CPZC + 1; i++) {
pdata->src2_tables[i] =
&_amsrc2tables[i * AM_SRC2_COFFS];
}
} else {
/* Scale for 32-bit ints */
pdata->src2_delta_c = 0;
pdata->src2_delta_n = 0;
pdata->src2_cover = 0;
}
/* Set the data */
/* Release the mutex */
return (prebuffer);
} /* am_src2_init() */
/*
* am_src2_size()
*
* Description:
* Determine the size of a buffer, in bytes, needed to hold the number
* of "samples" when they are converted. We adjust the size based on
* the number of source hardware channels.
*
* NOTE: This size of the buffer is based on 32-bit per sample.
*
* Arguments:
* audio_prinfo_t *prinfo Ptr to the channel's information
* int dir Direction, AUDIO_PLAY or AUDIO_RECORD
* int samples The number of samples
* int hw_channels Number of hardware channels
*
* Returns:
* size The max # of bytes any sample rate conversion
* step could need in buffer space
* AUDIO_FAILURE Couldn't find this size
*/
static size_t
int hw_channels)
{
return ((size_t)AUDIO_FAILURE);
}
/* Round up to maximum frame size if any leftover */
size++;
} else {
}
if (size % AUDIO_CHANNELS_STEREO) {
size++;
}
/* Scale for 32-bit ints */
size <<= AM_SRC2_SHIFT2;
/* Now adjust for the number of channels */
if (dir == AUDIO_PLAY) {
size *= hw_channels;
}
} else {
}
}
return (size);
} /* am_src2_size() */
/*
* am_src2_update()
*
* Description:
* Initialise the sample rate conversion private data structure. Here
* we (re-)initialise what we couldn't in am_src2_init().
*
* Arguments:
* audio_prinfo_t *ch_prinfo Ptr to the channel's information
* audio_prinfo_t *hw_prinfo Ptr to the Codec's information
* void *src_info Src information (not used)
* int dir Direction, AUDIO_PLAY or AUDIO_RECORD
*
* Returns:
* AUDIO_SUCCESS Initialisation succeeded
* AUDIO_FAILURE Initialisation failed
*/
/*ARGSUSED*/
static int
{
/* Get src data structure */
return (AUDIO_FAILURE);
}
/*
* Set direction dependent data. Note: we should probably do some
* checking here to make sure sane samples rates are being used.
* Not as strict as amsrc1 but there should be something.
*/
if (dir == AUDIO_PLAY) {
pdata->src2_outFs);
pdata->src2_outFs);
} else {
/*
* Increment the filter step size if there is any left over.
* Otherwise we can overrun the end of the input signal when
* downsampling as the rounding errors accumulate.
*/
pdata->src2_tsteps++;
}
}
return (AUDIO_SUCCESS);
} /* am_src2_update() */
/*
* am_src2_up_m()
*
* Description:
* Carry out upsampling on a mono buffer.
*
* Arguments:
* am_src2_data_t *parms Conversion parameters structure
* int inbuf The input buffer to convert
* int outbuf The converted audio buffer
* int samples The number of samples to convert
*
* Returns:
* >= 0 The number of samples after conversion
*/
static int
{
long long sum; /* Output sample value */
int k; /* Coefficient counter */
int *t; /* Pointer into table */
int count; /* Output sample counter */
int s_index; /* Input sample index */
int l_index; /* Last sample index */
int c_index; /* Starting coefficient index */
int rounding; /* For rounding to nearest index */
int outFs; /* Local copies of variables */
int cmod;
int cover;
int csteps;
int i_index;
int delta_c;
int **tables;
/* Initialise */
count = 0;
/* Continue until the end */
/* Starting coefficient */
/* Starting sample */
/*
* Calculate output sample. Note we work from right to left
* starting with the rightmost sample and going backwards.
* We do it this way so a while loop can be used for better
* efficiency. This relies on the fact that t[0] is always
* zero.
*/
sum = 0;
k = AM_SRC2_COFFS - 1;
while (k) {
}
/* Write out */
/* Increment counters and pointers */
}
/* Put back */
/* Copy to front */
return (count);
} /* am_src2_up_m() */
/*
* am_src2_up_s()
*
* Description:
* Carry out upsampling on a stereo buffer.
*
* Arguments:
* am_src2_data_t *parms Conversion parameters structure
* int inbuf The input buffer to convert
* int outbuf The converted audio buffer
* int samples The number of samples to convert
*
* Returns:
* > 0 The number of samples after conversion
*/
static int
{
long long sum_l; /* Output sample value */
long long sum_r; /* Output sample value */
int c; /* Coefficient value */
int *t; /* Pointer into table */
int k; /* Coefficient counter */
int count; /* Output sample counter */
int s_index; /* Input sample index */
int l_index; /* Last sample index */
int c_index; /* Starting coefficient index */
int rounding; /* For rounding to nearest index */
int outFs; /* Local copies of variables */
int cmod;
int cover;
int csteps;
int i_index;
int delta_c;
int **tables;
/* Initialise */
count = 0;
/* Continue until the end */
/* Starting coefficient */
/* Starting sample */
/*
* Calculate output sample. Note we work from right to left
* starting with the rightmost sample and going backwards.
* We do it this way so a while loop can be used for better
* efficiency. This relies on the fact that t[0] is always
* zero.
*/
k = AM_SRC2_COFFS - 1;
while (k) {
c = t[k--];
}
/* Write out */
/* Increment counters and pointers */
}
/* Put back */
/* Copy to front */
return (count);
} /* am_src2_up_s() */
/*
* am_src2_dn_m()
*
* Description:
* Carry out downsampling on a mono buffer.
*
* Arguments:
* am_src2_data_t *parms Conversion parameters structure
* int inbuf The input buffer to convert
* int outbuf The converted audio buffer
* int samples The number of samples to convert
*
* Returns:
* > 0 The number of samples after conversion
*/
static int
{
long long sum; /* Output sample value */
int count; /* Output sample counter */
int s_index; /* Input sample index */
int l_index; /* Last sample index */
int c_index; /* Starting coefficient index */
int rounding; /* For rounding to nearest index */
int outFs; /* Local copies of variables */
int inFs;
int cmod;
int cover;
int csteps;
int tsteps;
int *table;
int i_index;
int delta_c;
int delta_n;
/* Initialise */
count = 0;
/* Continue until the end */
/* Starting coefficient and sample */
/* Calculate output sample */
sum = 0;
while (c_index <= AM_SRC2_END) {
}
/* Write out */
/* Increment counters and pointers */
}
/* Put back */
/* Copy to front */
return (count);
} /* am_src2_dn_m() */
/*
* am_src2_dn_s()
*
* Description:
* Carry out downsampling on a stereo buffer.
*
* Arguments:
* am_src2_data_t *parms Conversion parameters structure
* int inbuf The input buffer to convert
* int outbuf The converted audio buffer
* int samples The number of samples to convert
*
* Returns:
* > 0 The number of samples after conversion
*/
static int
{
long long sum_l; /* Output sample value */
long long sum_r; /* Output sample value */
int c; /* Coefficient value */
int count; /* Output sample counter */
int s_index; /* Input sample index */
int l_index; /* Last sample index */
int c_index; /* Starting coefficient index */
int rounding; /* For rounding to nearest index */
int outFs; /* Local copies of variables */
int inFs;
int cmod;
int cover;
int csteps;
int *table;
int tsteps;
int i_index;
int delta_c;
int delta_n;
/* Initialise */
count = 0;
/* Continue until the end */
/* Starting coefficient and sample */
while (c_index <= AM_SRC2_END) {
}
/* Write out */
/* Increment counters and pointers */
}
/* Put back */
/* Copy to front */
return (count);
} /* am_src2_dn_s() */