📄 pcmdecode.c
字号:
/* <LIC_AMD_STD> * Copyright (C) 2003-2005 Advanced Micro Devices, Inc. All Rights Reserved. * * Unless otherwise designated in writing, this software and any related * documentation are the confidential proprietary information of AMD. * THESE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY * UNLESS OTHERWISE NOTED IN WRITING, EXPRESS OR IMPLIED WARRANTY OF ANY * KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, * NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE AND IN NO * EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER. * * AMD does not assume any responsibility for any errors which may appear * in the Materials nor any responsibility to support or update the * Materials. AMD retains the right to modify the Materials at any time, * without notice, and is not obligated to provide such modified * Materials to you. AMD is not obligated to furnish, support, or make * any further information available to you. * </LIC_AMD_STD> *//* <CTL_AMD_STD> * </CTL_AMD_STD> *//* <DOC_AMD_STD> * pcmdecode.c * </DOC_AMD_STD> */#if defined(WIN32) || defined(UNDER_CE) #include <windows.h>#endif#include <stdio.h>#include <stdlib.h>#if !defined(UNDER_CE) #include <fcntl.h> #endif#include <string.h> #include "mai_osal.h" /* needed for threads */#include "audio_change_info.h"#include "pcmdecode.h"#include "wavformats.h"#define DPRINTF(_str_) /* MAIOSDebugPrint _str_ */#define INFO_PRINTF(_str_) /* MAIOSDebugPrint _str_ */#define ERRORPRINTF(_str_) /* MAIOSDebugPrint _str_ */#define MAX_PROCESS_PER_CALL_WAVE_FORMAT_PCM 0xc00#define WAVE_FORMAT_AIFF_PCM 0xc001523wavheaderinfo_t wavheader;#if DO_RATECONVERSION_AND_DOWNMIX /* [ */#define USE_CUBIC_SPLINE_FILTER#define MAX_AUDIO_CHANNELS 8#define saturate16(xx) (short)((xx < -32768) ? -32768 : ((xx > 32767) ? 32767 : xx))int number_of_channels;int undownmixed_number_of_channels;int sampling_rate_conversion_factor;static short *conversion_buffer;static short *csr_buf_base;/* The assigned values are important, and are used in the calculation of the buffer length. */enum{ CSR_NONE = 0, CSR_OCTUPLE = 64, CSR_QUADRUPLE = 32, CSR_DOUBLE = 16, CSR_HALVE = 8, CSR_QUARTER = 4,};void close_src(void){ sampling_rate_conversion_factor = CSR_NONE; if (conversion_buffer != NULL) free(conversion_buffer); conversion_buffer = NULL; if (csr_buf_base != NULL) free(csr_buf_base); csr_buf_base = NULL;}#ifdef USE_CUBIC_SPLINE_FILTER#define SPLINE_FIR_LENGTH_MAX 4096typedef struct filter_fir_struct{ int elements; int output[4]; int *coef; int *writeptr; int *readptr; int *delay_line_end; int delay_line[SPLINE_FIR_LENGTH_MAX]; int delay_line_length; int *save;} FILTER_FIR, *PFILTER_FIR;static FILTER_FIR fir[MAX_AUDIO_CHANNELS];#define CS_F_FAC 0x4000int cubic_spline_4x0FIR_coef[4] ={ (int)(-0.0234 * CS_F_FAC), (int)( 0.2266 * CS_F_FAC), (int)( 0.8672 * CS_F_FAC), (int)(-0.0703 * CS_F_FAC),};int /* cs */ cubic_spline_2xFIR_coef[4] = // same as 4x1{ (int)(-0.0625 * CS_F_FAC), /* 1 step in the future */ (int)( 0.5625 * CS_F_FAC), /* time now */ (int)( 0.5625 * CS_F_FAC), /* 1 step in the past */ (int)(-0.0625 * CS_F_FAC), /* 2 steps in the past */};int cubic_spline_4x2FIR_coef[4] ={ (int)(-0.0703 * CS_F_FAC), (int)( 0.8672 * CS_F_FAC), (int)( 0.2266 * CS_F_FAC), (int)(-0.0234 * CS_F_FAC), };/* From Matlab script x = 0:20; y = [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 ] ; xx = 0:.25:20; yi = interp1(x,y,xx,'cubic') -0.0234 -0.0625 -0.0703 0 0.2266 0.5625 0.8672 1.0000 0.8672 0.5625 0.2266 0 -0.0703 -0.0625 -0.0234 0*//* The cubic-spline filter does a reasonable job with four taps. It is not as good as an 80-tap fir, but it is a lot less expensive.*/static void upsample_cubic_spline2x(short *input, short *output, int how_many, int channels) // assumes interleaved streams{ int cc, ii, temp; int loop = how_many/channels; int *coef; int acc; if ((input == NULL) || (output == NULL) ) return; for (cc = 0; cc < channels; cc++) { fir[cc].elements = 4; fir[cc].delay_line_end = fir[cc].delay_line + fir[cc].delay_line_length; } for (ii = 0; ii < loop; ii++) // de-interleave and copy to delay lines { for (cc = 0; cc < channels; cc++) { *fir[cc].writeptr++ = *input++; // left is first if (fir[cc].writeptr >= fir[cc].delay_line_end) // stay within circular buffer fir[cc].writeptr -= fir[cc].delay_line_length; } } while (loop--) { for (cc = 0; cc < channels; cc++) { coef = cubic_spline_2xFIR_coef; acc = 0x2000; // rounding fir[cc].save = fir[cc].readptr; // Note that this is the output from the input buffer--NOT the output buffer! for (ii = 0; ii < fir[cc].elements; ii++) /* do FIR convolution */ { acc += (*fir[cc].readptr--) * (*coef++); if (fir[cc].readptr < fir[cc].delay_line) fir[cc].readptr += fir[cc].delay_line_length; } fir[cc].readptr = fir[cc].save; temp = (int)(acc >> 14); *output++ = saturate16(temp); // write to output buffer } for (cc = 0; cc < channels; cc++) { fir[cc].readptr--; /* time now is actually 1 step in the past, for a group delay of 1 sample */ if (fir[cc].readptr < fir[cc].delay_line) fir[cc].readptr += fir[cc].delay_line_length; // Now output the next unmodified sample for a 2x upsample *output++ = (short)*fir[cc].readptr; fir[cc].readptr += 2; if (fir[cc].readptr >= fir[cc].delay_line_end) fir[cc].readptr -= fir[cc].delay_line_length; } }}static void upsample_cubic_spline4x(short *input, short *output, int how_many, int channels) // assumes interleaved streams{ int cc, ii, temp; int loop = how_many/channels; int *coef; int acc; if ((input == NULL) || (output == NULL) ) return; for (cc = 0; cc < channels; cc++) { fir[cc].elements = 4; fir[cc].delay_line_end = fir[cc].delay_line + fir[cc].delay_line_length; } for (ii = 0; ii < loop; ii++) // de-interleave and copy to delay lines { for (cc = 0; cc < channels; cc++) { *fir[cc].writeptr++ = *input++; // left is first if (fir[cc].writeptr >= fir[cc].delay_line_end) // stay within circular buffer fir[cc].writeptr -= fir[cc].delay_line_length; } } while (loop--) { for (cc = 0; cc < channels; cc++) { coef = cubic_spline_4x0FIR_coef; acc = 0x2000; // rounding fir[cc].save = fir[cc].readptr; // Note that this is from the input buffer--NOT the output buffer! for (ii = 0; ii < fir[cc].elements; ii++) /* do FIR convolution using 4 values */ { acc += (*fir[cc].readptr--) * (*coef++); if (fir[cc].readptr < fir[cc].delay_line) fir[cc].readptr += fir[cc].delay_line_length; } fir[cc].readptr = fir[cc].save; temp = (int)(acc >> 14); fir[cc].output[0] = saturate16(temp); coef = cubic_spline_2xFIR_coef; // same as 4x1FIR_coef would be acc = 0x2000; // rounding for (ii = 0; ii < fir[cc].elements; ii++) /* do FIR convolution using 4 values */ { acc += (*fir[cc].readptr--) * (*coef++); if (fir[cc].readptr < fir[cc].delay_line) fir[cc].readptr += fir[cc].delay_line_length; } fir[cc].readptr = fir[cc].save; temp = (int)(acc >> 14); fir[cc].output[1] = saturate16(temp); coef = cubic_spline_4x2FIR_coef; acc = 0x2000; // rounding for (ii = 0; ii < fir[cc].elements; ii++) /* do FIR convolution using 4 values */ { acc += (*fir[cc].readptr--) * (*coef++); if (fir[cc].readptr < fir[cc].delay_line) fir[cc].readptr += fir[cc].delay_line_length; } temp = (int)(acc >> 14); fir[cc].output[2] = saturate16(temp); fir[cc].readptr = fir[cc].save-1; /* time now is actually 1 step in the past, for a group delay of 1 sample */ if (fir[cc].readptr < fir[cc].delay_line) fir[cc].readptr += fir[cc].delay_line_length; // Now use the next unmodified sample for 4x3 upsample fir[cc].output[3] = *fir[cc].readptr; fir[cc].readptr += 2; /* move to the next input sample */ if (fir[cc].readptr >= fir[cc].delay_line_end) fir[cc].readptr -= fir[cc].delay_line_length; } /* interleave results */ for (ii = 0; ii < fir[0].elements; ii++) for (cc = 0; cc < channels; cc++) *output++ = fir[cc].output[ii]; }}#endif/* This is, for now, the classic add/drop-sample method without filtering, except where cubic spline is used. */static int csr_leftover;static short csr_leftoverbuf[32];static short *csr_buf;short *convert_sampling_rate(short *inbuf, int *length /* in bytes */) // assumes 16 bits per sample { int ii, jj; int loop; short *buf = inbuf; if ((inbuf == NULL) || (*length == 0)) return NULL; /* only do this if we are downsampling */ if ((sampling_rate_conversion_factor == CSR_HALVE) || (sampling_rate_conversion_factor == CSR_QUARTER)) { if (csr_buf_base == NULL) csr_buf_base = (short *)malloc(16384); if (csr_buf_base != NULL) { if (csr_leftover) { csr_buf = csr_buf_base; memcpy(csr_buf, csr_leftoverbuf, csr_leftover); memcpy(((unsigned char*)csr_buf) + csr_leftover, buf, *length); *length += csr_leftover; csr_leftover = 0; buf = csr_buf; } if (*length & 0xf) // odd lengths are a problem when downsampling { int slength = *length & 0xfffff0; csr_leftover = *length - slength; memcpy(csr_leftoverbuf, ((unsigned char*)buf) + slength, csr_leftover); *length = slength; } } } else if (csr_buf_base != NULL) { free(csr_buf_base); csr_buf_base = NULL; } loop = *length / sizeof(short); if (number_of_channels == 1) { switch (sampling_rate_conversion_factor) { case CSR_OCTUPLE: // FIXIT use a cubic spline for this one too for (jj = 0, ii = 0; ii < loop; ii++, jj += 8) { conversion_buffer[jj] = buf[ii]; conversion_buffer[jj+1] = buf[ii]; conversion_buffer[jj+2] = buf[ii]; conversion_buffer[jj+3] = buf[ii]; conversion_buffer[jj+4] = buf[ii]; conversion_buffer[jj+5] = buf[ii]; conversion_buffer[jj+6] = buf[ii]; conversion_buffer[jj+7] = buf[ii]; } *length *= 8; break; case CSR_QUADRUPLE: #ifdef USE_CUBIC_SPLINE_FILTER upsample_cubic_spline4x(buf, conversion_buffer, loop, 1); #else for (jj = 0, ii = 0; ii < loop; ii++, jj += 4) { conversion_buffer[jj] = buf[ii]; conversion_buffer[jj+1] = buf[ii]; conversion_buffer[jj+2] = buf[ii]; conversion_buffer[jj+3] = buf[ii]; } #endif *length *= 4; break; case CSR_DOUBLE: #ifdef USE_CUBIC_SPLINE_FILTER upsample_cubic_spline2x(buf, conversion_buffer, loop, 1); #else for (jj = 0, ii = 0; ii < loop; ii++, jj += 2) { conversion_buffer[jj] = buf[ii]; conversion_buffer[jj+1] = buf[ii]; } #endif *length *= 2; break; case CSR_HALVE: for (jj = 0, ii = 0; ii < loop; ii += 2, jj++) conversion_buffer[jj] = buf[ii]; *length /= 2; break; case CSR_QUARTER: for (jj = 0, ii = 0; ii < loop; ii += 4, jj++) conversion_buffer[jj] = buf[ii]; *length /= 4; break; default: // one to one, no rate conversion for (jj = 0; jj < loop; jj++) conversion_buffer[jj] = buf[jj]; break; } return conversion_buffer; } else if (number_of_channels == 2) /* interleaved stereo loops */ { switch (sampling_rate_conversion_factor) { case CSR_OCTUPLE: for (jj = 0, ii = 0; ii < loop; ii += 2, jj += 16) { conversion_buffer[jj] = buf[ii];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -