Last active
January 3, 2019 07:14
-
-
Save yoshimurawork/7561304 to your computer and use it in GitHub Desktop.
サンプルレート変換のコードです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <vector> | |
#include <cassert> | |
#include <cmath> | |
#include <algorithm> | |
namespace resample { | |
// 再近傍補間 (補間しない) | |
template <class T> | |
class InterpolationNearest | |
{ | |
public: | |
T operator()(const T& previous, const T& lower, const T& upper, const T& next, double amp) | |
{ | |
return amp > 0.5? upper : lower; | |
} | |
}; | |
typedef InterpolationNearest<float> InterpolationNearestf; | |
typedef InterpolationNearest<double> InterpolationNearestd; | |
// 線形補間 | |
template <class T> | |
class InterpolationLerp | |
{ | |
public: | |
T operator()(const T& previous, const T& lower, const T& upper, const T& next, double amp) | |
{ | |
return lower + (upper - lower) * amp; | |
} | |
}; | |
typedef InterpolationLerp<float> InterpolationLerpf; | |
typedef InterpolationLerp<double> InterpolationLerpd; | |
// ハーフコサイン補間 | |
template <class T> | |
class InterpolationHarfCos | |
{ | |
public: | |
T operator()(const T& previous, const T& lower, const T& upper, const T& next, double amp) | |
{ | |
return lower + (upper - lower) * (std::cos(M_PI + amp * M_PI) * 0.5 + 0.5); | |
} | |
}; | |
typedef InterpolationHarfCos<float> InterpolationHarfCosf; | |
typedef InterpolationHarfCos<double> InterpolationHarfCosd; | |
// Catmull-Rom 補間 | |
template <class T> | |
T catmull_rom(double t, const T& p0, const T& p1, const T& p2, const T& p3) | |
{ | |
return 0.5 * ( | |
(2.0 * p1) + | |
(-p0 + p2) * t + | |
(2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t * t + | |
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t * t * t | |
); | |
} | |
template <class T> | |
class InterpolationCatmulRom | |
{ | |
public: | |
T operator()(const T& previous, const T& lower, const T& upper, const T& next, double amp) | |
{ | |
return catmull_rom(amp, previous, lower, upper, next); | |
} | |
}; | |
typedef InterpolationCatmulRom<float> InterpolationCatmulRomf; | |
typedef InterpolationCatmulRom<double> InterpolationCatmulRomd; | |
/** | |
* 特定の間隔のデータ列から、任意のタイミングのデータを補間して取り出す | |
* @param sampleTime 任意のタイミング | |
* @param fromValues 元のデータ | |
* @param fromFrequency 元のデータの周波数 | |
* @param interpolation 補間アルゴリズム | |
*/ | |
template <class T, class U> | |
T sample(double sampleTime, | |
const std::vector<T>& fromValues, | |
double fromFrequency, | |
U interpolation) | |
{ | |
// エラーチェック | |
assert(sampleTime >= 0); | |
assert(fromFrequency > 0); | |
// 見に行く場所 | |
double fromStepMillisecond = 1000.0 / fromFrequency; | |
double lookup = sampleTime / fromStepMillisecond; | |
// ベースとなる位置 | |
int lookup_lower = std::min(static_cast<int>(std::floor(lookup)), static_cast<int>(fromValues.size()) - 1); | |
// 合わせて近接の値 | |
int lookup_previous = std::max(lookup_lower - 1, 0); | |
int lookup_upper = std::min(lookup_lower + 1, static_cast<int>(fromValues.size()) - 1); | |
int lookup_next = std::min(lookup_lower + 2, static_cast<int>(fromValues.size()) - 1); | |
// 0~1補間位置 | |
double amp = std::fmod(sampleTime, fromStepMillisecond) / fromStepMillisecond; | |
const T& value_previous = fromValues[lookup_previous]; | |
const T& value_lower = fromValues[lookup_lower]; | |
const T& value_upper = fromValues[lookup_upper]; | |
const T& value_next = fromValues[lookup_next]; | |
return interpolation(value_previous, value_lower, value_upper, value_next, amp); | |
} | |
/** | |
* 特定の間隔のデータ列から、任意の間隔のデータ列へとコンバートする | |
* @param toValues コンバート後のデータを入れる場所 | |
* @param fromValues 元のデータ | |
* @param fromFrequency 元のデータの周波数 | |
* @param interpolation 補間アルゴリズム | |
*/ | |
template <class T, class U> | |
void resmaple_write(std::vector<T>& toValues, | |
double toFrequency, | |
const std::vector<T>& fromValues, | |
double fromFrequency, | |
U interpolation) | |
{ | |
// エラーチェック | |
assert(fromValues.size()); | |
assert(toFrequency > 0); | |
assert(fromFrequency > 0); | |
// クリア | |
toValues.clear(); | |
// タイムステップ | |
double fromStepMillisecond = 1000.0 / fromFrequency; | |
double toStepMillisecond = 1000.0 / toFrequency; | |
// 適切なサイズを確保する | |
double durationMillisecond = fromValues.size() * fromStepMillisecond; | |
int requiredSize = static_cast<int>(round(durationMillisecond / toStepMillisecond)); | |
toValues.resize(requiredSize); | |
//書き出す | |
for(int i = 0 ; i < toValues.size() ; ++i) | |
{ | |
toValues[i] = sample(i * toStepMillisecond, fromValues, fromFrequency, interpolation); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment