Skip to content

Instantly share code, notes, and snippets.

@yoshimurawork
Last active January 3, 2019 07:14
Show Gist options
  • Save yoshimurawork/7561304 to your computer and use it in GitHub Desktop.
Save yoshimurawork/7561304 to your computer and use it in GitHub Desktop.
サンプルレート変換のコードです。
#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