在波形文件中查找狄拉克

时间:2018-07-06 17:03:53

标签: c++ audio audio-recording

这是关于房间校正的信息。

我有一个参考波文件,该文件通过立体声放大器播放并使用麦克风录制(umik 1)。

现在,我的问题是,我必须手动找到插入参考音频中的音阶(“咔嗒”声),并手动计算麦克风的时钟漂移。例如,在参考文件中,单击为0.5s,另一单击为62s。

在录制的文件中,点击次数略有减少。我目前正在检查wave文件,并根据两次点击之间的实际记录距离来计算实际时钟/采样率。

我如何识别此点击代码,并获取进行计算所需的信息?

1 个答案:

答案 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);
    }
}