【问题标题】:Find dirac in wave file在波形文件中查找狄拉克
【发布时间】:2018-07-06 17:03:52
【问题描述】:

这是关于房间校正的。

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

现在我的问题是我必须手动找到插入到参考音频中的狄拉克(响亮的“咔哒声”),并手动计算麦克风的时钟漂移。例如,在参考文件中,点击是 0.5 秒,另一个是 62 秒。

在记录的文件中,点击量略有下降。我目前正在检查波形文件,并根据两次点击之间的实际记录距离计算实际时钟/采样率。

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

【问题讨论】:

    标签: c++ audio audio-recording


    【解决方案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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-20
      • 1970-01-01
      • 1970-01-01
      • 2021-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-25
      相关资源
      最近更新 更多