| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| |
| /* |
| * A wrapper for resampling a numerous amount of sampling combinations. |
| */ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "signal_processing_library.h" |
| #include "resampler.h" |
| |
| |
| namespace webrtc |
| { |
| |
| Resampler::Resampler() |
| { |
| state1_ = NULL; |
| state2_ = NULL; |
| state3_ = NULL; |
| in_buffer_ = NULL; |
| out_buffer_ = NULL; |
| in_buffer_size_ = 0; |
| out_buffer_size_ = 0; |
| in_buffer_size_max_ = 0; |
| out_buffer_size_max_ = 0; |
| // we need a reset before we will work |
| my_in_frequency_khz_ = 0; |
| my_out_frequency_khz_ = 0; |
| my_mode_ = kResamplerMode1To1; |
| my_type_ = kResamplerInvalid; |
| slave_left_ = NULL; |
| slave_right_ = NULL; |
| } |
| |
| Resampler::Resampler(int inFreq, int outFreq, ResamplerType type) |
| { |
| state1_ = NULL; |
| state2_ = NULL; |
| state3_ = NULL; |
| in_buffer_ = NULL; |
| out_buffer_ = NULL; |
| in_buffer_size_ = 0; |
| out_buffer_size_ = 0; |
| in_buffer_size_max_ = 0; |
| out_buffer_size_max_ = 0; |
| // we need a reset before we will work |
| my_in_frequency_khz_ = 0; |
| my_out_frequency_khz_ = 0; |
| my_mode_ = kResamplerMode1To1; |
| my_type_ = kResamplerInvalid; |
| slave_left_ = NULL; |
| slave_right_ = NULL; |
| |
| Reset(inFreq, outFreq, type); |
| } |
| |
| Resampler::~Resampler() |
| { |
| if (state1_) |
| { |
| free(state1_); |
| } |
| if (state2_) |
| { |
| free(state2_); |
| } |
| if (state3_) |
| { |
| free(state3_); |
| } |
| if (in_buffer_) |
| { |
| free(in_buffer_); |
| } |
| if (out_buffer_) |
| { |
| free(out_buffer_); |
| } |
| if (slave_left_) |
| { |
| delete slave_left_; |
| } |
| if (slave_right_) |
| { |
| delete slave_right_; |
| } |
| } |
| |
| int Resampler::ResetIfNeeded(int inFreq, int outFreq, ResamplerType type) |
| { |
| int tmpInFreq_kHz = inFreq / 1000; |
| int tmpOutFreq_kHz = outFreq / 1000; |
| |
| if ((tmpInFreq_kHz != my_in_frequency_khz_) || (tmpOutFreq_kHz != my_out_frequency_khz_) |
| || (type != my_type_)) |
| { |
| return Reset(inFreq, outFreq, type); |
| } else |
| { |
| return 0; |
| } |
| } |
| |
| int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) |
| { |
| |
| if (state1_) |
| { |
| free(state1_); |
| state1_ = NULL; |
| } |
| if (state2_) |
| { |
| free(state2_); |
| state2_ = NULL; |
| } |
| if (state3_) |
| { |
| free(state3_); |
| state3_ = NULL; |
| } |
| if (in_buffer_) |
| { |
| free(in_buffer_); |
| in_buffer_ = NULL; |
| } |
| if (out_buffer_) |
| { |
| free(out_buffer_); |
| out_buffer_ = NULL; |
| } |
| if (slave_left_) |
| { |
| delete slave_left_; |
| slave_left_ = NULL; |
| } |
| if (slave_right_) |
| { |
| delete slave_right_; |
| slave_right_ = NULL; |
| } |
| |
| in_buffer_size_ = 0; |
| out_buffer_size_ = 0; |
| in_buffer_size_max_ = 0; |
| out_buffer_size_max_ = 0; |
| |
| // This might be overridden if parameters are not accepted. |
| my_type_ = type; |
| |
| // Start with a math exercise, Euclid's algorithm to find the gcd: |
| |
| int a = inFreq; |
| int b = outFreq; |
| int c = a % b; |
| while (c != 0) |
| { |
| a = b; |
| b = c; |
| c = a % b; |
| } |
| // b is now the gcd; |
| |
| // We need to track what domain we're in. |
| my_in_frequency_khz_ = inFreq / 1000; |
| my_out_frequency_khz_ = outFreq / 1000; |
| |
| // Scale with GCD |
| inFreq = inFreq / b; |
| outFreq = outFreq / b; |
| |
| // Do we need stereo? |
| if ((my_type_ & 0xf0) == 0x20) |
| { |
| // Change type to mono |
| type = static_cast<ResamplerType>( |
| ((static_cast<int>(type) & 0x0f) + 0x10)); |
| slave_left_ = new Resampler(inFreq, outFreq, type); |
| slave_right_ = new Resampler(inFreq, outFreq, type); |
| } |
| |
| if (inFreq == outFreq) |
| { |
| my_mode_ = kResamplerMode1To1; |
| } else if (inFreq == 1) |
| { |
| switch (outFreq) |
| { |
| case 2: |
| my_mode_ = kResamplerMode1To2; |
| break; |
| case 3: |
| my_mode_ = kResamplerMode1To3; |
| break; |
| case 4: |
| my_mode_ = kResamplerMode1To4; |
| break; |
| case 6: |
| my_mode_ = kResamplerMode1To6; |
| break; |
| case 12: |
| my_mode_ = kResamplerMode1To12; |
| break; |
| default: |
| my_type_ = kResamplerInvalid; |
| return -1; |
| } |
| } else if (outFreq == 1) |
| { |
| switch (inFreq) |
| { |
| case 2: |
| my_mode_ = kResamplerMode2To1; |
| break; |
| case 3: |
| my_mode_ = kResamplerMode3To1; |
| break; |
| case 4: |
| my_mode_ = kResamplerMode4To1; |
| break; |
| case 6: |
| my_mode_ = kResamplerMode6To1; |
| break; |
| case 12: |
| my_mode_ = kResamplerMode12To1; |
| break; |
| default: |
| my_type_ = kResamplerInvalid; |
| return -1; |
| } |
| } else if ((inFreq == 2) && (outFreq == 3)) |
| { |
| my_mode_ = kResamplerMode2To3; |
| } else if ((inFreq == 2) && (outFreq == 11)) |
| { |
| my_mode_ = kResamplerMode2To11; |
| } else if ((inFreq == 4) && (outFreq == 11)) |
| { |
| my_mode_ = kResamplerMode4To11; |
| } else if ((inFreq == 8) && (outFreq == 11)) |
| { |
| my_mode_ = kResamplerMode8To11; |
| } else if ((inFreq == 3) && (outFreq == 2)) |
| { |
| my_mode_ = kResamplerMode3To2; |
| } else if ((inFreq == 11) && (outFreq == 2)) |
| { |
| my_mode_ = kResamplerMode11To2; |
| } else if ((inFreq == 11) && (outFreq == 4)) |
| { |
| my_mode_ = kResamplerMode11To4; |
| } else if ((inFreq == 11) && (outFreq == 16)) |
| { |
| my_mode_ = kResamplerMode11To16; |
| } else if ((inFreq == 11) && (outFreq == 32)) |
| { |
| my_mode_ = kResamplerMode11To32; |
| } else if ((inFreq == 11) && (outFreq == 8)) |
| { |
| my_mode_ = kResamplerMode11To8; |
| } else |
| { |
| my_type_ = kResamplerInvalid; |
| return -1; |
| } |
| |
| // Now create the states we need |
| switch (my_mode_) |
| { |
| case kResamplerMode1To1: |
| // No state needed; |
| break; |
| case kResamplerMode1To2: |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| break; |
| case kResamplerMode1To3: |
| state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); |
| WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state1_); |
| break; |
| case kResamplerMode1To4: |
| // 1:2 |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| // 2:4 |
| state2_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); |
| break; |
| case kResamplerMode1To6: |
| // 1:2 |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| // 2:6 |
| state2_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); |
| WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state2_); |
| break; |
| case kResamplerMode1To12: |
| // 1:2 |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| // 2:4 |
| state2_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); |
| // 4:12 |
| state3_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); |
| WebRtcSpl_ResetResample16khzTo48khz( |
| (WebRtcSpl_State16khzTo48khz*) state3_); |
| break; |
| case kResamplerMode2To3: |
| // 2:6 |
| state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); |
| WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state1_); |
| // 6:3 |
| state2_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); |
| break; |
| case kResamplerMode2To11: |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| |
| state2_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz)); |
| WebRtcSpl_ResetResample8khzTo22khz((WebRtcSpl_State8khzTo22khz *)state2_); |
| break; |
| case kResamplerMode4To11: |
| state1_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz)); |
| WebRtcSpl_ResetResample8khzTo22khz((WebRtcSpl_State8khzTo22khz *)state1_); |
| break; |
| case kResamplerMode8To11: |
| state1_ = malloc(sizeof(WebRtcSpl_State16khzTo22khz)); |
| WebRtcSpl_ResetResample16khzTo22khz((WebRtcSpl_State16khzTo22khz *)state1_); |
| break; |
| case kResamplerMode11To16: |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| |
| state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); |
| WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state2_); |
| break; |
| case kResamplerMode11To32: |
| // 11 -> 22 |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| |
| // 22 -> 16 |
| state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); |
| WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state2_); |
| |
| // 16 -> 32 |
| state3_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state3_, 0, 8 * sizeof(WebRtc_Word32)); |
| |
| break; |
| case kResamplerMode2To1: |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| break; |
| case kResamplerMode3To1: |
| state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); |
| WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state1_); |
| break; |
| case kResamplerMode4To1: |
| // 4:2 |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| // 2:1 |
| state2_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); |
| break; |
| case kResamplerMode6To1: |
| // 6:2 |
| state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); |
| WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state1_); |
| // 2:1 |
| state2_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); |
| break; |
| case kResamplerMode12To1: |
| // 12:4 |
| state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); |
| WebRtcSpl_ResetResample48khzTo16khz( |
| (WebRtcSpl_State48khzTo16khz*) state1_); |
| // 4:2 |
| state2_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); |
| // 2:1 |
| state3_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state3_, 0, 8 * sizeof(WebRtc_Word32)); |
| break; |
| case kResamplerMode3To2: |
| // 3:6 |
| state1_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); |
| // 6:2 |
| state2_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); |
| WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state2_); |
| break; |
| case kResamplerMode11To2: |
| state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz)); |
| WebRtcSpl_ResetResample22khzTo8khz((WebRtcSpl_State22khzTo8khz *)state1_); |
| |
| state2_ = malloc(8 * sizeof(WebRtc_Word32)); |
| memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); |
| |
| break; |
| case kResamplerMode11To4: |
| state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz)); |
| WebRtcSpl_ResetResample22khzTo8khz((WebRtcSpl_State22khzTo8khz *)state1_); |
| break; |
| case kResamplerMode11To8: |
| state1_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); |
| WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state1_); |
| break; |
| |
| } |
| |
| return 0; |
| } |
| |
| // Synchronous resampling, all output samples are written to samplesOut |
| int Resampler::Push(const WebRtc_Word16 * samplesIn, int lengthIn, WebRtc_Word16* samplesOut, |
| int maxLen, int &outLen) |
| { |
| // Check that the resampler is not in asynchronous mode |
| if (my_type_ & 0x0f) |
| { |
| return -1; |
| } |
| |
| // Do we have a stereo signal? |
| if ((my_type_ & 0xf0) == 0x20) |
| { |
| |
| // Split up the signal and call the slave object for each channel |
| |
| WebRtc_Word16* left = (WebRtc_Word16*)malloc(lengthIn * sizeof(WebRtc_Word16) / 2); |
| WebRtc_Word16* right = (WebRtc_Word16*)malloc(lengthIn * sizeof(WebRtc_Word16) / 2); |
| WebRtc_Word16* out_left = (WebRtc_Word16*)malloc(maxLen / 2 * sizeof(WebRtc_Word16)); |
| WebRtc_Word16* out_right = |
| (WebRtc_Word16*)malloc(maxLen / 2 * sizeof(WebRtc_Word16)); |
| int res = 0; |
| for (int i = 0; i < lengthIn; i += 2) |
| { |
| left[i >> 1] = samplesIn[i]; |
| right[i >> 1] = samplesIn[i + 1]; |
| } |
| |
| // It's OK to overwrite the local parameter, since it's just a copy |
| lengthIn = lengthIn / 2; |
| |
| int actualOutLen_left = 0; |
| int actualOutLen_right = 0; |
| // Do resampling for right channel |
| res |= slave_left_->Push(left, lengthIn, out_left, maxLen / 2, actualOutLen_left); |
| res |= slave_right_->Push(right, lengthIn, out_right, maxLen / 2, actualOutLen_right); |
| if (res || (actualOutLen_left != actualOutLen_right)) |
| { |
| free(left); |
| free(right); |
| free(out_left); |
| free(out_right); |
| return -1; |
| } |
| |
| // Reassemble the signal |
| for (int i = 0; i < actualOutLen_left; i++) |
| { |
| samplesOut[i * 2] = out_left[i]; |
| samplesOut[i * 2 + 1] = out_right[i]; |
| } |
| outLen = 2 * actualOutLen_left; |
| |
| free(left); |
| free(right); |
| free(out_left); |
| free(out_right); |
| |
| return 0; |
| } |
| |
| // Containers for temp samples |
| WebRtc_Word16* tmp; |
| WebRtc_Word16* tmp_2; |
| // tmp data for resampling routines |
| WebRtc_Word32* tmp_mem; |
| |
| switch (my_mode_) |
| { |
| case kResamplerMode1To1: |
| memcpy(samplesOut, samplesIn, lengthIn * sizeof(WebRtc_Word16)); |
| outLen = lengthIn; |
| break; |
| case kResamplerMode1To2: |
| if (maxLen < (lengthIn * 2)) |
| { |
| return -1; |
| } |
| WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, (WebRtc_Word32*)state1_); |
| outLen = lengthIn * 2; |
| return 0; |
| case kResamplerMode1To3: |
| |
| // We can only handle blocks of 160 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 160) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < (lengthIn * 3)) |
| { |
| return -1; |
| } |
| tmp_mem = (WebRtc_Word32*)malloc(336 * sizeof(WebRtc_Word32)); |
| |
| for (int i = 0; i < lengthIn; i += 160) |
| { |
| WebRtcSpl_Resample16khzTo48khz(samplesIn + i, samplesOut + i * 3, |
| (WebRtcSpl_State16khzTo48khz *)state1_, |
| tmp_mem); |
| } |
| outLen = lengthIn * 3; |
| free(tmp_mem); |
| return 0; |
| case kResamplerMode1To4: |
| if (maxLen < (lengthIn * 4)) |
| { |
| return -1; |
| } |
| |
| tmp = (WebRtc_Word16*)malloc(sizeof(WebRtc_Word16) * 2 * lengthIn); |
| // 1:2 |
| WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); |
| // 2:4 |
| WebRtcSpl_UpsampleBy2(tmp, lengthIn * 2, samplesOut, (WebRtc_Word32*)state2_); |
| outLen = lengthIn * 4; |
| free(tmp); |
| return 0; |
| case kResamplerMode1To6: |
| // We can only handle blocks of 80 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 80) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < (lengthIn * 6)) |
| { |
| return -1; |
| } |
| |
| //1:2 |
| |
| tmp_mem = (WebRtc_Word32*)malloc(336 * sizeof(WebRtc_Word32)); |
| tmp = (WebRtc_Word16*)malloc(sizeof(WebRtc_Word16) * 2 * lengthIn); |
| |
| WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); |
| outLen = lengthIn * 2; |
| |
| for (int i = 0; i < outLen; i += 160) |
| { |
| WebRtcSpl_Resample16khzTo48khz(tmp + i, samplesOut + i * 3, |
| (WebRtcSpl_State16khzTo48khz *)state2_, |
| tmp_mem); |
| } |
| outLen = outLen * 3; |
| free(tmp_mem); |
| free(tmp); |
| |
| return 0; |
| case kResamplerMode1To12: |
| // We can only handle blocks of 40 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 40) != 0) { |
| return -1; |
| } |
| if (maxLen < (lengthIn * 12)) { |
| return -1; |
| } |
| |
| tmp_mem = (WebRtc_Word32*) malloc(336 * sizeof(WebRtc_Word32)); |
| tmp = (WebRtc_Word16*) malloc(sizeof(WebRtc_Word16) * 4 * lengthIn); |
| //1:2 |
| WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, |
| (WebRtc_Word32*) state1_); |
| outLen = lengthIn * 2; |
| //2:4 |
| WebRtcSpl_UpsampleBy2(samplesOut, outLen, tmp, (WebRtc_Word32*) state2_); |
| outLen = outLen * 2; |
| // 4:12 |
| for (int i = 0; i < outLen; i += 160) { |
| // WebRtcSpl_Resample16khzTo48khz() takes a block of 160 samples |
| // as input and outputs a resampled block of 480 samples. The |
| // data is now actually in 32 kHz sampling rate, despite the |
| // function name, and with a resampling factor of three becomes |
| // 96 kHz. |
| WebRtcSpl_Resample16khzTo48khz(tmp + i, samplesOut + i * 3, |
| (WebRtcSpl_State16khzTo48khz*) state3_, |
| tmp_mem); |
| } |
| outLen = outLen * 3; |
| free(tmp_mem); |
| free(tmp); |
| |
| return 0; |
| case kResamplerMode2To3: |
| if (maxLen < (lengthIn * 3 / 2)) |
| { |
| return -1; |
| } |
| // 2:6 |
| // We can only handle blocks of 160 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 160) != 0) |
| { |
| return -1; |
| } |
| tmp = static_cast<WebRtc_Word16*> (malloc(sizeof(WebRtc_Word16) * lengthIn * 3)); |
| tmp_mem = (WebRtc_Word32*)malloc(336 * sizeof(WebRtc_Word32)); |
| for (int i = 0; i < lengthIn; i += 160) |
| { |
| WebRtcSpl_Resample16khzTo48khz(samplesIn + i, tmp + i * 3, |
| (WebRtcSpl_State16khzTo48khz *)state1_, |
| tmp_mem); |
| } |
| lengthIn = lengthIn * 3; |
| // 6:3 |
| WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, (WebRtc_Word32*)state2_); |
| outLen = lengthIn / 2; |
| free(tmp); |
| free(tmp_mem); |
| return 0; |
| case kResamplerMode2To11: |
| |
| // We can only handle blocks of 80 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 80) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < ((lengthIn * 11) / 2)) |
| { |
| return -1; |
| } |
| tmp = (WebRtc_Word16*)malloc(sizeof(WebRtc_Word16) * 2 * lengthIn); |
| // 1:2 |
| WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); |
| lengthIn *= 2; |
| |
| tmp_mem = (WebRtc_Word32*)malloc(98 * sizeof(WebRtc_Word32)); |
| |
| for (int i = 0; i < lengthIn; i += 80) |
| { |
| WebRtcSpl_Resample8khzTo22khz(tmp + i, samplesOut + (i * 11) / 4, |
| (WebRtcSpl_State8khzTo22khz *)state2_, |
| tmp_mem); |
| } |
| outLen = (lengthIn * 11) / 4; |
| free(tmp_mem); |
| free(tmp); |
| return 0; |
| case kResamplerMode4To11: |
| |
| // We can only handle blocks of 80 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 80) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < ((lengthIn * 11) / 4)) |
| { |
| return -1; |
| } |
| tmp_mem = (WebRtc_Word32*)malloc(98 * sizeof(WebRtc_Word32)); |
| |
| for (int i = 0; i < lengthIn; i += 80) |
| { |
| WebRtcSpl_Resample8khzTo22khz(samplesIn + i, samplesOut + (i * 11) / 4, |
| (WebRtcSpl_State8khzTo22khz *)state1_, |
| tmp_mem); |
| } |
| outLen = (lengthIn * 11) / 4; |
| free(tmp_mem); |
| return 0; |
| case kResamplerMode8To11: |
| // We can only handle blocks of 160 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 160) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < ((lengthIn * 11) / 8)) |
| { |
| return -1; |
| } |
| tmp_mem = (WebRtc_Word32*)malloc(88 * sizeof(WebRtc_Word32)); |
| |
| for (int i = 0; i < lengthIn; i += 160) |
| { |
| WebRtcSpl_Resample16khzTo22khz(samplesIn + i, samplesOut + (i * 11) / 8, |
| (WebRtcSpl_State16khzTo22khz *)state1_, |
| tmp_mem); |
| } |
| outLen = (lengthIn * 11) / 8; |
| free(tmp_mem); |
| return 0; |
| |
| case kResamplerMode11To16: |
| // We can only handle blocks of 110 samples |
| if ((lengthIn % 110) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < ((lengthIn * 16) / 11)) |
| { |
| return -1; |
| } |
| |
| tmp_mem = (WebRtc_Word32*)malloc(104 * sizeof(WebRtc_Word32)); |
| tmp = (WebRtc_Word16*)malloc((sizeof(WebRtc_Word16) * lengthIn * 2)); |
| |
| WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); |
| |
| for (int i = 0; i < (lengthIn * 2); i += 220) |
| { |
| WebRtcSpl_Resample22khzTo16khz(tmp + i, samplesOut + (i / 220) * 160, |
| (WebRtcSpl_State22khzTo16khz *)state2_, |
| tmp_mem); |
| } |
| |
| outLen = (lengthIn * 16) / 11; |
| |
| free(tmp_mem); |
| free(tmp); |
| return 0; |
| |
| case kResamplerMode11To32: |
| |
| // We can only handle blocks of 110 samples |
| if ((lengthIn % 110) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < ((lengthIn * 32) / 11)) |
| { |
| return -1; |
| } |
| |
| tmp_mem = (WebRtc_Word32*)malloc(104 * sizeof(WebRtc_Word32)); |
| tmp = (WebRtc_Word16*)malloc((sizeof(WebRtc_Word16) * lengthIn * 2)); |
| |
| // 11 -> 22 kHz in samplesOut |
| WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, (WebRtc_Word32*)state1_); |
| |
| // 22 -> 16 in tmp |
| for (int i = 0; i < (lengthIn * 2); i += 220) |
| { |
| WebRtcSpl_Resample22khzTo16khz(samplesOut + i, tmp + (i / 220) * 160, |
| (WebRtcSpl_State22khzTo16khz *)state2_, |
| tmp_mem); |
| } |
| |
| // 16 -> 32 in samplesOut |
| WebRtcSpl_UpsampleBy2(tmp, (lengthIn * 16) / 11, samplesOut, |
| (WebRtc_Word32*)state3_); |
| |
| outLen = (lengthIn * 32) / 11; |
| |
| free(tmp_mem); |
| free(tmp); |
| return 0; |
| |
| case kResamplerMode2To1: |
| if (maxLen < (lengthIn / 2)) |
| { |
| return -1; |
| } |
| WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, samplesOut, (WebRtc_Word32*)state1_); |
| outLen = lengthIn / 2; |
| return 0; |
| case kResamplerMode3To1: |
| // We can only handle blocks of 480 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 480) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < (lengthIn / 3)) |
| { |
| return -1; |
| } |
| tmp_mem = (WebRtc_Word32*)malloc(496 * sizeof(WebRtc_Word32)); |
| |
| for (int i = 0; i < lengthIn; i += 480) |
| { |
| WebRtcSpl_Resample48khzTo16khz(samplesIn + i, samplesOut + i / 3, |
| (WebRtcSpl_State48khzTo16khz *)state1_, |
| tmp_mem); |
| } |
| outLen = lengthIn / 3; |
| free(tmp_mem); |
| return 0; |
| case kResamplerMode4To1: |
| if (maxLen < (lengthIn / 4)) |
| { |
| return -1; |
| } |
| tmp = (WebRtc_Word16*)malloc(sizeof(WebRtc_Word16) * lengthIn / 2); |
| // 4:2 |
| WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); |
| // 2:1 |
| WebRtcSpl_DownsampleBy2(tmp, lengthIn / 2, samplesOut, (WebRtc_Word32*)state2_); |
| outLen = lengthIn / 4; |
| free(tmp); |
| return 0; |
| |
| case kResamplerMode6To1: |
| // We can only handle blocks of 480 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 480) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < (lengthIn / 6)) |
| { |
| return -1; |
| } |
| |
| tmp_mem = (WebRtc_Word32*)malloc(496 * sizeof(WebRtc_Word32)); |
| tmp = (WebRtc_Word16*)malloc((sizeof(WebRtc_Word16) * lengthIn) / 3); |
| |
| for (int i = 0; i < lengthIn; i += 480) |
| { |
| WebRtcSpl_Resample48khzTo16khz(samplesIn + i, tmp + i / 3, |
| (WebRtcSpl_State48khzTo16khz *)state1_, |
| tmp_mem); |
| } |
| outLen = lengthIn / 3; |
| free(tmp_mem); |
| WebRtcSpl_DownsampleBy2(tmp, outLen, samplesOut, (WebRtc_Word32*)state2_); |
| free(tmp); |
| outLen = outLen / 2; |
| return 0; |
| case kResamplerMode12To1: |
| // We can only handle blocks of 480 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 480) != 0) { |
| return -1; |
| } |
| if (maxLen < (lengthIn / 12)) { |
| return -1; |
| } |
| |
| tmp_mem = (WebRtc_Word32*) malloc(496 * sizeof(WebRtc_Word32)); |
| tmp = (WebRtc_Word16*) malloc((sizeof(WebRtc_Word16) * lengthIn) / 3); |
| tmp_2 = (WebRtc_Word16*) malloc((sizeof(WebRtc_Word16) * lengthIn) / 6); |
| // 12:4 |
| for (int i = 0; i < lengthIn; i += 480) { |
| // WebRtcSpl_Resample48khzTo16khz() takes a block of 480 samples |
| // as input and outputs a resampled block of 160 samples. The |
| // data is now actually in 96 kHz sampling rate, despite the |
| // function name, and with a resampling factor of 1/3 becomes |
| // 32 kHz. |
| WebRtcSpl_Resample48khzTo16khz(samplesIn + i, tmp + i / 3, |
| (WebRtcSpl_State48khzTo16khz*) state1_, |
| tmp_mem); |
| } |
| outLen = lengthIn / 3; |
| free(tmp_mem); |
| // 4:2 |
| WebRtcSpl_DownsampleBy2(tmp, outLen, tmp_2, |
| (WebRtc_Word32*) state2_); |
| outLen = outLen / 2; |
| free(tmp); |
| // 2:1 |
| WebRtcSpl_DownsampleBy2(tmp_2, outLen, samplesOut, |
| (WebRtc_Word32*) state3_); |
| free(tmp_2); |
| outLen = outLen / 2; |
| return 0; |
| case kResamplerMode3To2: |
| if (maxLen < (lengthIn * 2 / 3)) |
| { |
| return -1; |
| } |
| // 3:6 |
| tmp = static_cast<WebRtc_Word16*> (malloc(sizeof(WebRtc_Word16) * lengthIn * 2)); |
| WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); |
| lengthIn *= 2; |
| // 6:2 |
| // We can only handle blocks of 480 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 480) != 0) |
| { |
| free(tmp); |
| return -1; |
| } |
| tmp_mem = (WebRtc_Word32*)malloc(496 * sizeof(WebRtc_Word32)); |
| for (int i = 0; i < lengthIn; i += 480) |
| { |
| WebRtcSpl_Resample48khzTo16khz(tmp + i, samplesOut + i / 3, |
| (WebRtcSpl_State48khzTo16khz *)state2_, |
| tmp_mem); |
| } |
| outLen = lengthIn / 3; |
| free(tmp); |
| free(tmp_mem); |
| return 0; |
| case kResamplerMode11To2: |
| // We can only handle blocks of 220 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 220) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < ((lengthIn * 2) / 11)) |
| { |
| return -1; |
| } |
| tmp_mem = (WebRtc_Word32*)malloc(126 * sizeof(WebRtc_Word32)); |
| tmp = (WebRtc_Word16*)malloc((lengthIn * 4) / 11 * sizeof(WebRtc_Word16)); |
| |
| for (int i = 0; i < lengthIn; i += 220) |
| { |
| WebRtcSpl_Resample22khzTo8khz(samplesIn + i, tmp + (i * 4) / 11, |
| (WebRtcSpl_State22khzTo8khz *)state1_, |
| tmp_mem); |
| } |
| lengthIn = (lengthIn * 4) / 11; |
| |
| WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, (WebRtc_Word32*)state2_); |
| outLen = lengthIn / 2; |
| |
| free(tmp_mem); |
| free(tmp); |
| return 0; |
| case kResamplerMode11To4: |
| // We can only handle blocks of 220 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 220) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < ((lengthIn * 4) / 11)) |
| { |
| return -1; |
| } |
| tmp_mem = (WebRtc_Word32*)malloc(126 * sizeof(WebRtc_Word32)); |
| |
| for (int i = 0; i < lengthIn; i += 220) |
| { |
| WebRtcSpl_Resample22khzTo8khz(samplesIn + i, samplesOut + (i * 4) / 11, |
| (WebRtcSpl_State22khzTo8khz *)state1_, |
| tmp_mem); |
| } |
| outLen = (lengthIn * 4) / 11; |
| free(tmp_mem); |
| return 0; |
| case kResamplerMode11To8: |
| // We can only handle blocks of 160 samples |
| // Can be fixed, but I don't think it's needed |
| if ((lengthIn % 220) != 0) |
| { |
| return -1; |
| } |
| if (maxLen < ((lengthIn * 8) / 11)) |
| { |
| return -1; |
| } |
| tmp_mem = (WebRtc_Word32*)malloc(104 * sizeof(WebRtc_Word32)); |
| |
| for (int i = 0; i < lengthIn; i += 220) |
| { |
| WebRtcSpl_Resample22khzTo16khz(samplesIn + i, samplesOut + (i * 8) / 11, |
| (WebRtcSpl_State22khzTo16khz *)state1_, |
| tmp_mem); |
| } |
| outLen = (lengthIn * 8) / 11; |
| free(tmp_mem); |
| return 0; |
| break; |
| |
| } |
| return 0; |
| } |
| |
| // Asynchronous resampling, input |
| int Resampler::Insert(WebRtc_Word16 * samplesIn, int lengthIn) |
| { |
| if (my_type_ != kResamplerAsynchronous) |
| { |
| return -1; |
| } |
| int sizeNeeded, tenMsblock; |
| |
| // Determine need for size of outBuffer |
| sizeNeeded = out_buffer_size_ + ((lengthIn + in_buffer_size_) * my_out_frequency_khz_) |
| / my_in_frequency_khz_; |
| if (sizeNeeded > out_buffer_size_max_) |
| { |
| // Round the value upwards to complete 10 ms blocks |
| tenMsblock = my_out_frequency_khz_ * 10; |
| sizeNeeded = (sizeNeeded / tenMsblock + 1) * tenMsblock; |
| out_buffer_ = (WebRtc_Word16*)realloc(out_buffer_, sizeNeeded * sizeof(WebRtc_Word16)); |
| out_buffer_size_max_ = sizeNeeded; |
| } |
| |
| // If we need to use inBuffer, make sure all input data fits there. |
| |
| tenMsblock = my_in_frequency_khz_ * 10; |
| if (in_buffer_size_ || (lengthIn % tenMsblock)) |
| { |
| // Check if input buffer size is enough |
| if ((in_buffer_size_ + lengthIn) > in_buffer_size_max_) |
| { |
| // Round the value upwards to complete 10 ms blocks |
| sizeNeeded = ((in_buffer_size_ + lengthIn) / tenMsblock + 1) * tenMsblock; |
| in_buffer_ = (WebRtc_Word16*)realloc(in_buffer_, |
| sizeNeeded * sizeof(WebRtc_Word16)); |
| in_buffer_size_max_ = sizeNeeded; |
| } |
| // Copy in data to input buffer |
| memcpy(in_buffer_ + in_buffer_size_, samplesIn, lengthIn * sizeof(WebRtc_Word16)); |
| |
| // Resample all available 10 ms blocks |
| int lenOut; |
| int dataLenToResample = (in_buffer_size_ / tenMsblock) * tenMsblock; |
| Push(in_buffer_, dataLenToResample, out_buffer_ + out_buffer_size_, |
| out_buffer_size_max_ - out_buffer_size_, lenOut); |
| out_buffer_size_ += lenOut; |
| |
| // Save the rest |
| memmove(in_buffer_, in_buffer_ + dataLenToResample, |
| (in_buffer_size_ - dataLenToResample) * sizeof(WebRtc_Word16)); |
| in_buffer_size_ -= dataLenToResample; |
| } else |
| { |
| // Just resample |
| int lenOut; |
| Push(in_buffer_, lengthIn, out_buffer_ + out_buffer_size_, |
| out_buffer_size_max_ - out_buffer_size_, lenOut); |
| out_buffer_size_ += lenOut; |
| } |
| |
| return 0; |
| } |
| |
| // Asynchronous resampling output, remaining samples are buffered |
| int Resampler::Pull(WebRtc_Word16* samplesOut, int desiredLen, int &outLen) |
| { |
| if (my_type_ != kResamplerAsynchronous) |
| { |
| return -1; |
| } |
| |
| // Check that we have enough data |
| if (desiredLen <= out_buffer_size_) |
| { |
| // Give out the date |
| memcpy(samplesOut, out_buffer_, desiredLen * sizeof(WebRtc_Word32)); |
| |
| // Shuffle down remaining |
| memmove(out_buffer_, out_buffer_ + desiredLen, |
| (out_buffer_size_ - desiredLen) * sizeof(WebRtc_Word16)); |
| |
| // Update remaining size |
| out_buffer_size_ -= desiredLen; |
| |
| return 0; |
| } else |
| { |
| return -1; |
| } |
| } |
| |
| } // namespace webrtc |