Changeset View
Changeset View
Standalone View
Standalone View
extern/audaspace/src/respec/JOSResampleReader.cpp
- This file was moved from intern/audaspace/intern/AUD_JOSResampleReader.cpp.
| /* | /******************************************************************************* | ||||
| * ***** BEGIN GPL LICENSE BLOCK ***** | * Copyright 2009-2016 Jörg Müller | ||||
| * | * | ||||
| * Copyright 2009-2011 Jörg Hermann Müller | * 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 | |||||
| * | * | ||||
| * This file is part of AudaSpace. | * http://www.apache.org/licenses/LICENSE-2.0 | ||||
| * | * | ||||
| * Audaspace is free software; you can redistribute it and/or modify | * Unless required by applicable law or agreed to in writing, software | ||||
| * it under the terms of the GNU General Public License as published by | * distributed under the License is distributed on an "AS IS" BASIS, | ||||
| * the Free Software Foundation; either version 2 of the License, or | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| * (at your option) any later version. | * See the License for the specific language governing permissions and | ||||
| * | * limitations under the License. | ||||
| * AudaSpace is distributed in the hope that it will be useful, | ******************************************************************************/ | ||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU General Public License | |||||
| * along with Audaspace; if not, write to the Free Software Foundation, | |||||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
| * | |||||
| * ***** END GPL LICENSE BLOCK ***** | |||||
| */ | |||||
| /** \file audaspace/intern/AUD_JOSResampleReader.cpp | |||||
| * \ingroup audaspaceintern | |||||
| */ | |||||
| #include "AUD_JOSResampleReader.h" | #include "respec/JOSResampleReader.h" | ||||
| #include "AUD_JOSResampleReaderCoeff.cpp" | |||||
| #include <algorithm> | |||||
| #include <cmath> | #include <cmath> | ||||
| #include <cstring> | #include <cstring> | ||||
| #include <iostream> | |||||
| /* MSVC does not have lrint */ | |||||
| #ifdef _MSC_VER | |||||
| #if _MSC_VER < 1800 | |||||
| #ifdef _M_X64 | |||||
| #include <emmintrin.h> | |||||
| static inline int lrint(double d) | |||||
| { | |||||
| return _mm_cvtsd_si32(_mm_load_sd(&d)); | |||||
| } | |||||
| #else | |||||
| static inline int lrint(double d) | |||||
| { | |||||
| int i; | |||||
| _asm{ | |||||
| fld d | |||||
| fistp i | |||||
| }; | |||||
| return i; | |||||
| } | |||||
| #endif | |||||
| #endif | |||||
| #endif | |||||
| // UNUSED | #define RATE_MAX 256 | ||||
| // #define CC m_channels + channel | |||||
| #define AUD_RATE_MAX 256 | |||||
| #define SHIFT_BITS 12 | #define SHIFT_BITS 12 | ||||
| #define double_to_fp(x) (lrint(x * double(1 << SHIFT_BITS))) | #define double_to_fp(x) (lrint(x * double(1 << SHIFT_BITS))) | ||||
| #define int_to_fp(x) (x << SHIFT_BITS) | #define int_to_fp(x) (x << SHIFT_BITS) | ||||
| Context not available. | |||||
| #define fp_rest(x) (x & ((1 << SHIFT_BITS) - 1)) | #define fp_rest(x) (x & ((1 << SHIFT_BITS) - 1)) | ||||
| #define fp_rest_to_double(x) fp_to_double(fp_rest(x)) | #define fp_rest_to_double(x) fp_to_double(fp_rest(x)) | ||||
| AUD_JOSResampleReader::AUD_JOSResampleReader(boost::shared_ptr<AUD_IReader> reader, AUD_Specs specs) : | AUD_NAMESPACE_BEGIN | ||||
| AUD_ResampleReader(reader, specs.rate), | |||||
| m_channels(AUD_CHANNELS_INVALID), | JOSResampleReader::JOSResampleReader(std::shared_ptr<IReader> reader, SampleRate rate) : | ||||
| ResampleReader(reader, rate), | |||||
| m_channels(CHANNELS_INVALID), | |||||
| m_n(0), | m_n(0), | ||||
| m_P(0), | m_P(0), | ||||
| m_cache_valid(0), | m_cache_valid(0), | ||||
| Context not available. | |||||
| { | { | ||||
| } | } | ||||
| void AUD_JOSResampleReader::reset() | void JOSResampleReader::reset() | ||||
| { | { | ||||
| m_cache_valid = 0; | m_cache_valid = 0; | ||||
| m_n = 0; | m_n = 0; | ||||
| Context not available. | |||||
| m_last_factor = 0; | m_last_factor = 0; | ||||
| } | } | ||||
| void AUD_JOSResampleReader::updateBuffer(int size, double factor, int samplesize) | void JOSResampleReader::updateBuffer(int size, double factor, int samplesize) | ||||
| { | { | ||||
| unsigned int len; | unsigned int len; | ||||
| double num_samples = double(m_len) / double(m_L); | double num_samples = double(m_len) / double(m_L); | ||||
| // first calculate what length we need right now | // first calculate what length we need right now | ||||
| if(factor >= 1) | if(factor >= 1) | ||||
| len = ceil(num_samples); | len = std::ceil(num_samples); | ||||
| else | else | ||||
| len = (unsigned int)(ceil(num_samples / factor)); | len = (unsigned int)(std::ceil(num_samples / factor)); | ||||
| // then check if afterwards the length is enough for the maximum rate | // then check if afterwards the length is enough for the maximum rate | ||||
| if(len + size < num_samples * AUD_RATE_MAX) | if(len + size < num_samples * RATE_MAX) | ||||
| len = num_samples * AUD_RATE_MAX - size; | len = num_samples * RATE_MAX - size; | ||||
| if(m_n > len) | if(m_n > len) | ||||
| { | { | ||||
| sample_t* buf = m_buffer.getBuffer(); | sample_t* buf = m_buffer.getBuffer(); | ||||
| len = m_n - len; | len = m_n - len; | ||||
| memmove(buf, buf + len * m_channels, (m_cache_valid - len) * samplesize); | std::memmove(buf, buf + len * m_channels, (m_cache_valid - len) * samplesize); | ||||
| m_n -= len; | m_n -= len; | ||||
| m_cache_valid -= len; | m_cache_valid -= len; | ||||
| } | } | ||||
| Context not available. | |||||
| m_buffer.assureSize((m_cache_valid + size) * samplesize, true); | m_buffer.assureSize((m_cache_valid + size) * samplesize, true); | ||||
| } | } | ||||
| #define RESAMPLE_METHOD(name, left, right) void AUD_JOSResampleReader::name(double target_factor, int length, sample_t* buffer)\ | #define RESAMPLE_METHOD(name, left, right) void JOSResampleReader::name(double target_factor, int length, sample_t* buffer)\ | ||||
| {\ | {\ | ||||
| sample_t* buf = m_buffer.getBuffer();\ | sample_t* buf = m_buffer.getBuffer();\ | ||||
| \ | \ | ||||
| Context not available. | |||||
| {\ | {\ | ||||
| factor = (m_last_factor * (length - t - 1) + target_factor * (t + 1)) / length;\ | factor = (m_last_factor * (length - t - 1) + target_factor * (t + 1)) / length;\ | ||||
| \ | \ | ||||
| memset(sums, 0, sizeof(double) * m_channels);\ | std::memset(sums, 0, sizeof(double) * m_channels);\ | ||||
| \ | \ | ||||
| if(factor >= 1)\ | if(factor >= 1)\ | ||||
| {\ | {\ | ||||
| P = double_to_fp(m_P * m_L);\ | P = double_to_fp(m_P * m_L);\ | ||||
| \ | \ | ||||
| end = floor(m_len / double(m_L) - m_P) - 1;\ | end = std::floor(m_len / double(m_L) - m_P) - 1;\ | ||||
| if(m_n < end)\ | if(m_n < end)\ | ||||
| end = m_n;\ | end = m_n;\ | ||||
| \ | \ | ||||
| Context not available. | |||||
| \ | \ | ||||
| P = int_to_fp(m_L) - P;\ | P = int_to_fp(m_L) - P;\ | ||||
| \ | \ | ||||
| end = floor((m_len - 1) / double(m_L) + m_P) - 1;\ | end = std::floor((m_len - 1) / double(m_L) + m_P) - 1;\ | ||||
| if(m_cache_valid - m_n - 2 < end)\ | if(m_cache_valid - m_n - 2 < end)\ | ||||
| end = m_cache_valid - m_n - 2;\ | end = m_cache_valid - m_n - 2;\ | ||||
| \ | \ | ||||
| Context not available. | |||||
| \ | \ | ||||
| for(channel = 0; channel < m_channels; channel++)\ | for(channel = 0; channel < m_channels; channel++)\ | ||||
| {\ | {\ | ||||
| *buffer = factor * sums[channel];\ | *buffer = factor * sums[channel];\ | ||||
| buffer++;\ | buffer++;\ | ||||
| }\ | }\ | ||||
| }\ | }\ | ||||
| \ | \ | ||||
| m_P += fmod(1.0 / factor, 1.0);\ | m_P += std::fmod(1.0 / factor, 1.0);\ | ||||
| m_n += floor(1.0 / factor);\ | m_n += std::floor(1.0 / factor);\ | ||||
| \ | \ | ||||
| while(m_P >= 1.0)\ | while(m_P >= 1.0)\ | ||||
| {\ | {\ | ||||
| Context not available. | |||||
| sums[1] += data[2] * v; | sums[1] += data[2] * v; | ||||
| }) | }) | ||||
| void AUD_JOSResampleReader::seek(int position) | void JOSResampleReader::seek(int position) | ||||
| { | { | ||||
| position = floor(position * double(m_reader->getSpecs().rate) / double(m_rate)); | position = std::floor(position * double(m_reader->getSpecs().rate) / double(m_rate)); | ||||
| m_reader->seek(position); | m_reader->seek(position); | ||||
| reset(); | reset(); | ||||
| } | } | ||||
| int AUD_JOSResampleReader::getLength() const | int JOSResampleReader::getLength() const | ||||
| { | { | ||||
| return floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate)); | return std::floor(m_reader->getLength() * double(m_rate) / double(m_reader->getSpecs().rate)); | ||||
| } | } | ||||
| int AUD_JOSResampleReader::getPosition() const | int JOSResampleReader::getPosition() const | ||||
| { | { | ||||
| return floor((m_reader->getPosition() + double(m_P)) | return std::floor((m_reader->getPosition() + double(m_P)) * m_rate / m_reader->getSpecs().rate); | ||||
| * m_rate / m_reader->getSpecs().rate); | |||||
| } | } | ||||
| AUD_Specs AUD_JOSResampleReader::getSpecs() const | Specs JOSResampleReader::getSpecs() const | ||||
| { | { | ||||
| AUD_Specs specs = m_reader->getSpecs(); | Specs specs = m_reader->getSpecs(); | ||||
| specs.rate = m_rate; | specs.rate = m_rate; | ||||
| return specs; | return specs; | ||||
| } | } | ||||
| void AUD_JOSResampleReader::read(int& length, bool& eos, sample_t* buffer) | void JOSResampleReader::read(int& length, bool& eos, sample_t* buffer) | ||||
| { | { | ||||
| if(length == 0) | if(length == 0) | ||||
| return; | return; | ||||
| AUD_Specs specs = m_reader->getSpecs(); | Specs specs = m_reader->getSpecs(); | ||||
| int samplesize = AUD_SAMPLE_SIZE(specs); | int samplesize = AUD_SAMPLE_SIZE(specs); | ||||
| double target_factor = double(m_rate) / double(specs.rate); | double target_factor = double(m_rate) / double(specs.rate); | ||||
| Context not available. | |||||
| switch(m_channels) | switch(m_channels) | ||||
| { | { | ||||
| case AUD_CHANNELS_MONO: | case CHANNELS_MONO: | ||||
| m_resample = &AUD_JOSResampleReader::resample_mono; | m_resample = &JOSResampleReader::resample_mono; | ||||
| break; | break; | ||||
| case AUD_CHANNELS_STEREO: | case CHANNELS_STEREO: | ||||
| m_resample = &AUD_JOSResampleReader::resample_stereo; | m_resample = &JOSResampleReader::resample_stereo; | ||||
| break; | break; | ||||
| default: | default: | ||||
| m_resample = &AUD_JOSResampleReader::resample; | m_resample = &JOSResampleReader::resample; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| if(length > 0) | if(length > 0) | ||||
| { | { | ||||
| memcpy(buffer, buf + m_n * m_channels, length * samplesize); | std::memcpy(buffer, buf + m_n * m_channels, length * samplesize); | ||||
| m_n += length; | m_n += length; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| // use minimum for the following calculations | // use minimum for the following calculations | ||||
| double factor = AUD_MIN(target_factor, m_last_factor); | double factor = std::min(target_factor, m_last_factor); | ||||
| if(factor >= 1) | if(factor >= 1) | ||||
| len = (int(m_n) - m_cache_valid) + int(ceil(length / factor)) + ceil(num_samples); | len = (int(m_n) - m_cache_valid) + int(std::ceil(length / factor)) + std::ceil(num_samples); | ||||
| else | else | ||||
| len = (int(m_n) - m_cache_valid) + int(ceil(length / factor) + ceil(num_samples / factor)); | len = (int(m_n) - m_cache_valid) + int(std::ceil(length / factor) + std::ceil(num_samples / factor)); | ||||
| if(len > 0) | if(len > 0) | ||||
| { | { | ||||
| Context not available. | |||||
| else | else | ||||
| { | { | ||||
| // use maximum for the following calculations | // use maximum for the following calculations | ||||
| factor = AUD_MAX(target_factor, m_last_factor); | factor = std::max(target_factor, m_last_factor); | ||||
| if(eos) | if(eos) | ||||
| { | { | ||||
| // end of stream, let's check how many more samples we can produce | // end of stream, let's check how many more samples we can produce | ||||
| len = floor((m_cache_valid - m_n) * factor); | len = std::floor((m_cache_valid - m_n) * factor); | ||||
| if(len < length) | if(len < length) | ||||
| length = len; | length = len; | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| // not enough data available yet, so we recalculate how many samples we can calculate | // not enough data available yet, so we recalculate how many samples we can calculate | ||||
| if(factor >= 1) | if(factor >= 1) | ||||
| len = floor((num_samples + m_cache_valid - m_n) * factor); | len = std::floor((num_samples + m_cache_valid - m_n) * factor); | ||||
| else | else | ||||
| len = floor((num_samples * factor + m_cache_valid - m_n) * factor); | len = std::floor((num_samples * factor + m_cache_valid - m_n) * factor); | ||||
| if(len < length) | if(len < length) | ||||
| length = len; | length = len; | ||||
| } | } | ||||
| Context not available. | |||||
| eos = eos && ((m_n == m_cache_valid) || (length == 0)); | eos = eos && ((m_n == m_cache_valid) || (length == 0)); | ||||
| } | } | ||||
| AUD_NAMESPACE_END | |||||
| Context not available. | |||||