| /* ------------------------------------------------------------------ |
| * Copyright (C) 1998-2009 PacketVideo |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| * express or implied. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * ------------------------------------------------------------------- |
| */ |
| /* |
| ------------------------------------------------------------------------------ |
| |
| PacketVideo Corp. |
| MP3 Decoder Library |
| |
| Filename: pvmp3_stereo_proc.cpp |
| |
| Functions: |
| |
| pvmp3_st_mid_side |
| pvmp3_st_intensity |
| pvmp3_stereo_proc |
| |
| ------------------------------------------------------------------------------ |
| |
| pvmp3_st_mid_side |
| |
| INPUT AND OUTPUT DEFINITIONS |
| |
| Input |
| |
| int32 xr[], input channel |
| int32 xl[], |
| int32 Start, Location of first element where stereo intensity is applied |
| int32 Number number of elements affected |
| |
| Returns |
| |
| int32 xl[], generated stereo channel |
| |
| |
| ------------------------------------------------------------------------------ |
| |
| pvmp3_st_intensity |
| |
| INPUT AND OUTPUT DEFINITIONS |
| |
| Input |
| |
| int32 xr[], input channel |
| int32 xl[], |
| int32 is_pos, index to table is_ratio_factor[] |
| int32 Start, Location of first element where stereo intensity is applied |
| int32 Number number of elements affected |
| |
| Returns |
| |
| int32 xl[], generated stereo channel |
| |
| |
| ------------------------------------------------------------------------------ |
| |
| pvmp3_stereo_proc |
| |
| INPUT AND OUTPUT DEFINITIONS |
| |
| Input |
| |
| int32 xr[], input channel |
| int32 xl[], |
| mp3ScaleFactors *scalefac, scale factors structure |
| struct gr_info_s *gr_info, granule structure |
| mp3Header *info mp3 header info |
| Returns |
| |
| int32 xl[], generated stereo channel |
| |
| |
| ------------------------------------------------------------------------------ |
| FUNCTION DESCRIPTION |
| |
| stereo processing for mpeg1 layer III |
| After requantization, the reconstructed values are processed for ms_stereo |
| or intensity_stereo modes or both, before passing them to the synthesis |
| filterbank |
| |
| In ms_stereo mode the values of the normalized middle/side channels |
| M[l] and S[l] are transmitted instead of the left/right channel values |
| L[l] and R[l]. From here, L[l] and R[l] are reconstructed |
| |
| Intensity_stereo is done by specifying the magnitude (via the |
| scalefactors of the left channel) and a stereo position is_pos[sfb], |
| which is transmitted instead of scalefactors of the right channel. |
| The stereo position is used to derive the left and right channel signals |
| |
| ------------------------------------------------------------------------------ |
| REQUIREMENTS |
| |
| |
| ------------------------------------------------------------------------------ |
| REFERENCES |
| |
| [1] ISO MPEG Audio Subgroup Software Simulation Group (1996) |
| ISO 13818-3 MPEG-2 Audio Decoder - Lower Sampling Frequency Extension |
| |
| ------------------------------------------------------------------------------ |
| PSEUDO-CODE |
| |
| ------------------------------------------------------------------------------ |
| */ |
| |
| |
| /*---------------------------------------------------------------------------- |
| ; INCLUDES |
| ----------------------------------------------------------------------------*/ |
| |
| #include "pvmp3_stereo_proc.h" |
| #include "pv_mp3dec_fxd_op.h" |
| #include "pvmp3_tables.h" |
| |
| |
| /*---------------------------------------------------------------------------- |
| ; MACROS |
| ; Define module specific macros here |
| ----------------------------------------------------------------------------*/ |
| |
| |
| /*---------------------------------------------------------------------------- |
| ; DEFINES |
| ; Include all pre-processor statements here. Include conditional |
| ; compile variables also. |
| ----------------------------------------------------------------------------*/ |
| #define N31 31 |
| |
| #define Q31_fmt(a) (int32(double(0x7FFFFFFF)*(a))) |
| |
| /*---------------------------------------------------------------------------- |
| ; LOCAL FUNCTION DEFINITIONS |
| ; Function Prototype declaration |
| ----------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------- |
| ; LOCAL STORE/BUFFER/POINTER DEFINITIONS |
| ; Variable declaration - defined here and used outside this module |
| ----------------------------------------------------------------------------*/ |
| /* |
| * TmpFac= tan(is_pos * (PI /12)); |
| * |
| * TmpFac /= (1 + TmpFac); |
| * |
| */ |
| |
| const int32 is_ratio_factor[8] = {0, |
| Q31_fmt(0.21132486540519), Q31_fmt(0.36602540378444), Q31_fmt(0.50000000000000), |
| Q31_fmt(0.63397459621556), Q31_fmt(0.78867513459481), Q31_fmt(1.00000000000000), |
| 0 |
| }; |
| |
| /*---------------------------------------------------------------------------- |
| ; EXTERNAL FUNCTION REFERENCES |
| ; Declare functions defined elsewhere and referenced in this module |
| ----------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------- |
| ; EXTERNAL GLOBAL STORE/BUFFER/POINTER REFERENCES |
| ; Declare variables used in this module but defined elsewhere |
| ----------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------- |
| ; FUNCTION CODE |
| ----------------------------------------------------------------------------*/ |
| |
| #if __has_attribute(no_sanitize) |
| // deliberately playing near overflow points of int32 |
| __attribute__((no_sanitize("integer"))) |
| #endif |
| void pvmp3_st_mid_side(int32 xr[SUBBANDS_NUMBER*FILTERBANK_BANDS], |
| int32 xl[SUBBANDS_NUMBER*FILTERBANK_BANDS], |
| int32 Start, |
| int32 Number) |
| { |
| |
| int32 *pt_xr = &xr[Start]; |
| int32 *pt_xl = &xl[Start]; |
| |
| for (int32 i = Number >> 1; i != 0; i--) |
| { |
| int32 xxr = *(pt_xr) << 1; |
| int32 xxl = *(pt_xl) << 1; |
| *(pt_xr++) = fxp_mul32_Q32((xxr + xxl), Q31_fmt(0.70710678118655)); /* Sum */ |
| *(pt_xl++) = fxp_mul32_Q32((xxr - xxl), Q31_fmt(0.70710678118655)); /* Diff */ |
| xxr = *(pt_xr) << 1; |
| xxl = *(pt_xl) << 1; |
| *(pt_xr++) = fxp_mul32_Q32((xxr + xxl), Q31_fmt(0.70710678118655)); /* Sum */ |
| *(pt_xl++) = fxp_mul32_Q32((xxr - xxl), Q31_fmt(0.70710678118655)); /* Diff */ |
| } |
| |
| |
| if (Number&1) |
| { |
| int32 xxr = *(pt_xr) << 1; |
| int32 xxl = *(pt_xl) << 1; |
| *(pt_xr) = fxp_mul32_Q32((xxr + xxl), Q31_fmt(0.70710678118655)); /* Sum */ |
| *(pt_xl) = fxp_mul32_Q32((xxr - xxl), Q31_fmt(0.70710678118655)); /* Diff */ |
| } |
| |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| ; FUNCTION CODE |
| ----------------------------------------------------------------------------*/ |
| |
| void pvmp3_st_intensity(int32 xr[SUBBANDS_NUMBER*FILTERBANK_BANDS], |
| int32 xl[SUBBANDS_NUMBER*FILTERBANK_BANDS], |
| int32 is_pos, |
| int32 Start, |
| int32 Number) |
| { |
| |
| int32 TmpFac = is_ratio_factor[ is_pos & 7]; |
| |
| int32 *pt_xr = &xr[Start]; |
| int32 *pt_xl = &xl[Start]; |
| |
| for (int32 i = Number >> 1; i != 0; i--) |
| { |
| int32 tmp = fxp_mul32_Q32((*pt_xr) << 1, TmpFac); |
| *(pt_xl++) = (*pt_xr) - tmp; |
| *(pt_xr++) = tmp; |
| tmp = fxp_mul32_Q32((*pt_xr) << 1, TmpFac); |
| *(pt_xl++) = (*pt_xr) - tmp; |
| *(pt_xr++) = tmp; |
| } |
| |
| if (Number&1) |
| { |
| int32 tmp = fxp_mul32_Q32((*pt_xr) << 1, TmpFac); |
| *(pt_xl) = (*pt_xr) - tmp; |
| *(pt_xr) = tmp; |
| } |
| |
| } |
| |
| /*---------------------------------------------------------------------------- |
| ; FUNCTION CODE |
| ----------------------------------------------------------------------------*/ |
| void pvmp3_stereo_proc(int32 xr[SUBBANDS_NUMBER*FILTERBANK_BANDS], |
| int32 xl[SUBBANDS_NUMBER*FILTERBANK_BANDS], |
| mp3ScaleFactors *scalefac, |
| granuleInfo *gr_info, |
| int32 used_freq_lines, |
| mp3Header *info) |
| { |
| |
| |
| int32 sb; |
| int32 ss; |
| int32 sfbNo; |
| int32 sfbStart; |
| |
| int32 sfb; |
| int32 sfbTemp; |
| int32 i; |
| int32 j; |
| |
| |
| int32 i_stereo = (info->mode == MPG_MD_JOINT_STEREO) && |
| (info->mode_ext & 0x1); |
| |
| int32 ms_stereo = (info->mode == MPG_MD_JOINT_STEREO) && |
| (info->mode_ext & 0x2); |
| |
| int32 sfreq = info->version_x + (info->version_x << 1); |
| sfreq += info->sampling_frequency; |
| |
| |
| |
| |
| if (i_stereo) |
| { |
| if (gr_info->window_switching_flag && (gr_info->block_type == 2)) |
| { |
| if (gr_info->mixed_block_flag) |
| { |
| /* |
| * mixed blocks processing |
| */ |
| i = 31; |
| ss = 17; |
| sb = 0; |
| while (i >= 0) |
| { |
| if (xl[(i*FILTERBANK_BANDS) + ss]) |
| { |
| sb = (i << 4) + (i << 1) + ss; |
| i = -1; |
| } |
| else |
| { |
| ss--; |
| if (ss < 0) |
| { |
| i--; |
| ss = 17; |
| } |
| } |
| } |
| |
| if (sb < 36) |
| { |
| /* |
| * mixed blocks processing: intensity bound inside long blocks |
| */ |
| /* 1. long blocks up to intensity border: not intensity */ |
| |
| if (mp3_sfBandIndex[sfreq].l[4] <= sb) |
| { |
| sfb = 4; |
| } |
| else |
| { |
| sfb = 0; |
| } |
| |
| while (mp3_sfBandIndex[sfreq].l[sfb] < sb) |
| { |
| sfb++; |
| } |
| |
| /* from that sfb on intensity stereo */ |
| sfbTemp = sfb; /* save for later use */ |
| |
| sfbStart = mp3_sfBandIndex[sfreq].l[sfb]; |
| |
| /* from 0 up to sfbStart do ms_stereo or normal stereo */ |
| |
| if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, 0, sfbStart); |
| } |
| |
| /* 2. long blocks from intensity border up to sfb band 8: intensity */ |
| /* calc. is_ratio */ |
| |
| |
| /* Start of intensity stereo of remaining sfc bands: */ |
| for (; sfbTemp < 8; sfbTemp++) |
| { |
| sfbStart = mp3_sfBandIndex[sfreq].l[sfbTemp]; /* = Start in 0 ... 575 */ |
| sfbNo = mp3_sfBandIndex[sfreq].l[sfbTemp+1] - mp3_sfBandIndex[sfreq].l[sfbTemp]; /* No of lines to process */ |
| |
| if (scalefac->l[sfbTemp] != 7) |
| { |
| pvmp3_st_intensity(xr, xl, scalefac->l[sfbTemp], sfbStart, sfbNo); |
| } |
| else if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, sfbStart, sfbNo); |
| } |
| |
| } /* for (; sfbTemp < 8; sfbTemp++) */ |
| |
| for (j = 0; j < 3; j++) |
| { |
| /* 3. short blocks from sfbcnt to last sfb do intensity stereo */ |
| for (sfbTemp = 3; sfbTemp < 13; sfbTemp++) |
| { |
| sfbNo = mp3_sfBandIndex[sfreq].s[sfbTemp+1] - mp3_sfBandIndex[sfreq].s[sfbTemp]; /* No of lines to process */ |
| sfbStart = 3 * mp3_sfBandIndex[sfreq].s[sfbTemp] + j * sfbNo; |
| |
| if (scalefac->s[j][sfbTemp] != 7) |
| { |
| pvmp3_st_intensity(xr, xl, scalefac->s[j][sfbTemp], sfbStart, sfbNo); |
| } |
| else if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, sfbStart, sfbNo); |
| } |
| |
| } /* for (; sfbTemp < 22; sfbTemp++) */ |
| } /* for (j = 0; j < 3; j++) */ |
| } |
| else /* else for (sb >= 36) */ |
| { |
| /* |
| * mixed blocks processing: intensity bound outside long blocks |
| */ |
| |
| |
| /* |
| * 2. short blocks from sfb band 3 up to intensity border: normal stereo, ms stereo and intensity |
| */ |
| for (j = 0; j < 3; j++) |
| { |
| int32 sfbcnt; |
| sfbcnt = -1; |
| |
| for (sfb = 12; sfb >= 3; sfb--) |
| { |
| int32 lines; |
| lines = mp3_sfBandIndex[sfreq].s[sfb+1] - mp3_sfBandIndex[sfreq].s[sfb]; |
| i = 3 * mp3_sfBandIndex[sfreq].s[sfb] + (j + 1) * lines - 1; |
| |
| while (lines > 0) |
| { |
| if (xl[i]) |
| { |
| sfbcnt = sfb; |
| sfb = -10; |
| lines = -10; |
| } |
| lines--; |
| i--; |
| } |
| } |
| |
| sfbcnt += 1; |
| if (sfbcnt < 3) |
| { |
| sfbcnt = 3; |
| } |
| |
| sfbTemp = sfbcnt; /* for later use */ |
| |
| |
| /* |
| * do normal stereo or MS stereo from sfb 3 to < sfbcnt: |
| */ |
| for (sb = 3; sb < sfbcnt; sb++) |
| { |
| sfbNo = mp3_sfBandIndex[sfreq].s[sb+1] - mp3_sfBandIndex[sfreq].s[sb]; |
| sfbStart = 3 * mp3_sfBandIndex[sfreq].s[sb] + j * sfbNo; |
| |
| if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, sfbStart, sfbNo); |
| } |
| |
| } |
| |
| /* from sfbcnt to last sfb do intensity stereo */ |
| for (; sfbTemp < 13; sfbTemp++) |
| { |
| sfbNo = mp3_sfBandIndex[sfreq].s[sfbTemp+1] - mp3_sfBandIndex[sfreq].s[sfbTemp]; /* No of lines to process */ |
| sfbStart = 3 * mp3_sfBandIndex[sfreq].s[sfbTemp] + j * sfbNo; |
| |
| if (scalefac->s[j][sfbTemp] != 7) |
| { |
| pvmp3_st_intensity(xr, xl, scalefac->s[j][sfbTemp], sfbStart, sfbNo); |
| } |
| else if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, sfbStart, sfbNo); |
| } |
| |
| } /* for (; sfbTemp < 22; sfbTemp++) */ |
| |
| } /* for (j = 0; j < 3; j++) */ |
| |
| /* 1. long blocks up to sfb band 8: not intensity */ |
| /* from 0 to sfb 8 ms_stereo or normal stereo */ |
| |
| sfbStart = mp3_sfBandIndex[sfreq].l[8]; |
| |
| if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, 0, sfbStart); |
| } |
| |
| } |
| } /* if (gr_info->mixed_block_flag) */ |
| else |
| { |
| /* |
| * short block processing |
| */ |
| for (j = 0; j < 3; j++) |
| { |
| int32 sfbcnt = -1; |
| |
| for (sfb = 12; sfb >= 0; sfb--) |
| { |
| int32 lines = mp3_sfBandIndex[sfreq].s[sfb+1] - mp3_sfBandIndex[sfreq].s[sfb]; |
| i = 3 * mp3_sfBandIndex[sfreq].s[sfb] + (j + 1) * lines - 1; |
| |
| while (lines > 0) |
| { |
| if (xl[i]) |
| { |
| sfbcnt = sfb; |
| sfb = -10; |
| lines = -10; |
| } |
| lines--; |
| i--; |
| } |
| } |
| |
| sfbcnt += 1; |
| sfbTemp = sfbcnt; /* for later use */ |
| |
| /* do normal stereo or MS stereo from 0 to sfbcnt */ |
| for (sb = 0; sb < sfbcnt; sb++) |
| { |
| sfbNo = mp3_sfBandIndex[sfreq].s[sb+1] - mp3_sfBandIndex[sfreq].s[sb]; |
| sfbStart = 3 * mp3_sfBandIndex[sfreq].s[sb] + j * sfbNo; |
| |
| if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, sfbStart, sfbNo); |
| } |
| } |
| |
| |
| /* from sfbcnt to last sfb do intensity stereo */ |
| for (; sfbTemp < 13; sfbTemp++) |
| { |
| sfbNo = mp3_sfBandIndex[sfreq].s[sfbTemp+1] - mp3_sfBandIndex[sfreq].s[sfbTemp]; /* No of lines to process */ |
| sfbStart = 3 * mp3_sfBandIndex[sfreq].s[sfbTemp] + j * sfbNo; |
| |
| if (scalefac->s[j][sfbTemp] != 7) |
| { |
| pvmp3_st_intensity(xr, xl, scalefac->s[j][sfbTemp], sfbStart, sfbNo); |
| } |
| else if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, sfbStart, sfbNo); |
| } |
| |
| } /* for (; sfbTemp < 22; sfbTemp++) */ |
| |
| } /* for (j = 0; j < 3; j++) */ |
| |
| } /* if( gr_info->mixed_block_flag) */ |
| |
| |
| |
| } /* if (gr_info->window_switching_flag && (gr_info->block_type == 2)) */ |
| else |
| { |
| /* |
| * long block processing |
| */ |
| i = 31; |
| ss = 17; |
| sb = 0; |
| |
| while (i >= 0) |
| { |
| if (xl[(i*FILTERBANK_BANDS) + ss] != 0) |
| { |
| sb = (i << 4) + (i << 1) + ss; |
| i = -2; |
| } |
| else |
| { |
| ss--; |
| if (ss < 0) |
| { |
| i--; |
| ss = 17; |
| } |
| } |
| } |
| |
| if (sb) |
| { |
| if (mp3_sfBandIndex[sfreq].l[14] <= sb) |
| { |
| sfb = 14; |
| } |
| else if (mp3_sfBandIndex[sfreq].l[7] <= sb) |
| { |
| sfb = 7; |
| } |
| else |
| { |
| sfb = 0; |
| } |
| |
| |
| while (mp3_sfBandIndex[sfreq].l[sfb] <= sb) |
| { |
| sfb++; |
| } |
| } |
| else |
| { |
| if (i == -1) |
| { |
| /* all xr[1][][] are 0: set IS bound sfb to 0 */ |
| sfb = 0; |
| } |
| else |
| { |
| /* xr[1][0][0] is unequal 0 and all others are 0: set IS bound sfb to 1 */ |
| sfb = 1; |
| } |
| } |
| |
| sfbTemp = sfb; /* save for later use */ |
| |
| |
| sfbStart = mp3_sfBandIndex[sfreq].l[sfb]; |
| |
| /* from 0 to sfbStart ms_stereo or normal stereo */ |
| if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, 0, sfbStart); |
| } |
| |
| /* now intensity stereo of the remaining sfb's: */ |
| for (; sfb < 21; sfb++) |
| { |
| sfbStart = mp3_sfBandIndex[sfreq].l[sfb]; |
| sfbNo = mp3_sfBandIndex[sfreq].l[sfb+1] - mp3_sfBandIndex[sfreq].l[sfb]; /* No of lines to process */ |
| |
| if (scalefac->l[sfb] != 7) |
| { |
| pvmp3_st_intensity(xr, xl, scalefac->l[sfb], sfbStart, sfbNo); |
| } |
| else if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, sfbStart, sfbNo); |
| } |
| |
| } /* for (; sfbTemp < 22; sfbTemp++) */ |
| |
| |
| |
| sfbStart = mp3_sfBandIndex[sfreq].l[21]; |
| sfbNo = mp3_sfBandIndex[sfreq].l[22] - mp3_sfBandIndex[sfreq].l[21]; /* No of lines to process */ |
| |
| if (scalefac->l[21] != 7) |
| { |
| if (sfbTemp < 21) |
| { |
| sfbTemp = scalefac->l[20]; |
| } |
| else |
| { |
| sfbTemp = 0; /* if scalefac[20] is not an intensity position, is_pos = 0 */ |
| } |
| |
| pvmp3_st_intensity(xr, xl, sfbTemp, sfbStart, sfbNo); |
| } |
| else if (ms_stereo) |
| { |
| pvmp3_st_mid_side(xr, xl, sfbStart, sfbNo); |
| } |
| |
| } /* if (gr_info->window_switching_flag && (gr_info->block_type == 2)) */ |
| |
| |
| } /* if (i_stereo) */ |
| else |
| { |
| /* |
| * normal or ms stereo processing |
| */ |
| if (ms_stereo) |
| { |
| |
| pvmp3_st_mid_side(xr, xl, 0, used_freq_lines); |
| |
| } |
| |
| } /* if (i_stereo) */ |
| |
| } |
| |