这是关于房间校正的信息。
我有一个参考波文件,该文件通过立体声放大器播放并使用麦克风录制(umik 1)。
现在,我的问题是,我必须手动找到插入参考音频中的音阶(“咔嗒”声),并手动计算麦克风的时钟漂移。例如,在参考文件中,单击为0.5s,另一单击为62s。
在录制的文件中,点击次数略有减少。我目前正在检查wave文件,并根据两次点击之间的实际记录距离来计算实际时钟/采样率。
我如何识别此点击代码,并获取进行计算所需的信息?
答案 0 :(得分:1)
您可以:
noise_level
阈值的样本 find_relevant_start
实现了此目的,您可以像这样使用它:
// You may need to adjust `noise_level` based on the characteristics of your audio.
constexpr auto noise_level = 0.1f;
std::vector<float> audio;
auto it = find_relevant_start(audio.begin(), audio.end(), noise_level);
if(it==audio.end()) {
// not found, maybe 'noise_level' was too high?
}
这是代码(来自个人项目):
/*
* @param abs_relevant_level : if the absolute value of the signal
* is bigger than this value, it is considered to be relevant.
* Use a non-zero value if your signal contains noise.
*/
template<typename ITER, typename VAL = typename ITER::value_type>
ITER first_relevant_value(ITER it, ITER end, VAL abs_relevant_level) {
for(; it != end; ++ it ) {
if(std::abs(*it) > abs_relevant_level) {
break;
}
}
return it;
}
template<typename ITER>
ITER first_zero_crossing(ITER it, ITER end) {
using VAL = typename ITER::value_type;
using Tr = NumTraits<VAL>;
bool first = true;
VAL prev;
while(it != end) {
auto cur = *it;
if(cur == Tr::zero()) {
break;
}
if(first) {
first = false;
}
else if(prev * cur < Tr::zero()) {
break;
}
prev = cur;
++it;
}
return it;
}
template<typename ITER, typename VAL = typename ITER::value_type>
ITER find_relevant_start(ITER it, ITER end, VAL abs_relevant_level) {
auto it_relevant_value = first_relevant_value(it, end, abs_relevant_level);
if(it_relevant_value == end) {
return end;
}
using REVERSE_ITER = std::reverse_iterator<ITER>;
auto rit = REVERSE_ITER(it_relevant_value + 1);
auto rend = REVERSE_ITER(it);
auto rzero = first_zero_crossing( rit, rend);
// first_zero_crossing returns the iterator after the zero crossing (in the reverse direction)
// so rzero.base() is the iterator on the other side of the zero crossing
return rzero.base();
}
这些单元测试将向您展示其在简单数组上的性能:
TEST(Peaks, find_relevant_start)
{
using namespace imajuscule;
{
std::vector<float> v{ -0.04f, -0.03f, -0.02f, -0.01f, 0.1f, 0.2f, 0.3f };
auto it = find_relevant_start(v.begin(), v.end(), 0.15f);
ASSERT_EQ(0.1f, *it);
}
{
std::vector<float> v{ -0.04f, -0.03f, -0.02f, -0.01f, 0.1f, 0.2f, 0.3f };
auto it = find_relevant_start(v.begin(), v.end(), 0.25f);
// the algorithm finds the first relevant value, and goes backward from there to find the first sign change and returns the sample just after
ASSERT_EQ(0.1f, *it);
}
{
std::vector<float> v{ 0.04f, 0.03f, 0.02f, 0.01f, -0.1f, -0.2f, -0.3f };
auto it = find_relevant_start(v.begin(), v.end(), 0.25f);
// the algorithm finds the first relevant value, and goes backward from there to find the first sign change and returns the sample just after
ASSERT_EQ(-0.1f, *it);
}
{
std::vector<float> v{ -0.04f, -0.03f, -0.02f, -0.01f, 0.1f, 0.2f, 0.3f };
auto it = find_relevant_start(v.begin(), v.end(), 0.5f);
// the level is too high and was never reached so "end" should be returned
ASSERT_EQ(v.end(), it);
}
{
std::vector<float> v{ 1.f, 2.f, 1.f };
auto it = find_relevant_start(v.begin(), v.end(), 0.5f);
ASSERT_EQ(v.begin(), it);
}
{
std::vector<float> v{ -1.f, -2.f, -1.f };
auto it = find_relevant_start(v.begin(), v.end(), 0.5f);
ASSERT_EQ(v.begin(), it);
}
{
std::vector<float> v;
auto it = find_relevant_start(v.begin(), v.end(), 0.5f);
ASSERT_EQ(v.end(), it);
}
{
std::vector<float> v{.1f};
auto it = find_relevant_start(v.begin(), v.end(), 0.5f);
ASSERT_EQ(v.end(), it);
}
{
std::vector<float> v{1.f};
auto it = find_relevant_start(v.begin(), v.end(), 0.5f);
ASSERT_EQ(1.f, *it);
}
{
std::vector<float> v{-1.f};
auto it = find_relevant_start(v.begin(), v.end(), 0.5f);
ASSERT_EQ(-1.f, *it);
}
}