• 【Audio】正弦波生成原理及C++代码


    正弦波生成及频谱分析

    正弦波公式

    • 诊断系统(Diag)会通过播放一段指定频率、采样率、时长及振幅的正弦音,以此对Audio测试。
    • 正弦波的公式如下,其中 A是振幅、x是时间、F是频率。
      y = A ∗ sin ⁡ ( 2 ∗ π ∗ x ∗ F ) y = A* \sin \lparen 2 * \pi * x * F \rparen y=Asin(2πxF)

    当振幅是1.0 ,频率是1.0(频率指一秒钟震几次)。正弦波公式及其图像为
    y = sin ⁡ ( 2 π x ) y = \sin \lparen 2 \pi x \rparen y=sin(2πx)
    在这里插入图片描述

    • 考虑到相偏移θ和Y轴偏移量D(比如为了方便计算振幅不存在负数,那么Y轴向上偏移),其公式为
      y = A ∗ sin ⁡ ( 2 ∗ π ∗ x ∗ F + θ ) + D y = A* \sin \lparen 2 * \pi * x * F + \theta \rparen + D y=Asin(2πxF+θ)+D

    C++生成正弦波

    • WebRTC中提供了一段正弦波的生成函数,生成精度比较高。可以借鉴其代码,编写正弦波函数(改造后的实际应用代码不便放出)。这里分析一下WebRTC 正弦波生成源码。
    // webrtc/modules/audio_mixer/sine_wave_generator.h
    /*
     *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
     *
     *  Use of this source code is governed by a BSD-style license
     *  that can be found in the LICENSE file in the root of the source
     *  tree. An additional intellectual property rights grant can be found
     *  in the file PATENTS.  All contributing project authors may
     *  be found in the AUTHORS file in the root of the source tree.
     */
    
    #ifndef MODULES_AUDIO_MIXER_SINE_WAVE_GENERATOR_H_
    #define MODULES_AUDIO_MIXER_SINE_WAVE_GENERATOR_H_
    
    #include 
    
    #include "api/audio/audio_frame.h"
    #include "rtc_base/checks.h"
    
    namespace webrtc {
    
    class SineWaveGenerator {
     public:
      SineWaveGenerator(float wave_frequency_hz, int16_t amplitude)
          : wave_frequency_hz_(wave_frequency_hz), amplitude_(amplitude) {
        RTC_DCHECK_GT(wave_frequency_hz, 0);
      }
    
      // Produces appropriate output based on frame->num_channels_,
      // frame->sample_rate_hz_.
      // 通过这个函数生成正弦波
      void GenerateNextFrame(AudioFrame* frame);
    
     private:
      float phase_ = 0.f;
      // 正弦波频率
      const float wave_frequency_hz_;
      // 振幅
      const int16_t amplitude_;
    };
    
    }  // namespace webrtc
    
    #endif  // MODULES_AUDIO_MIXER_SINE_WAVE_GENERATOR_H_
    
    // webrtc/modules/audio_mixer/sine_wave_generator.cc
    /*
     *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
     *
     *  Use of this source code is governed by a BSD-style license
     *  that can be found in the LICENSE file in the root of the source
     *  tree. An additional intellectual property rights grant can be found
     *  in the file PATENTS.  All contributing project authors may
     *  be found in the AUTHORS file in the root of the source tree.
     */
    
    #include "modules/audio_mixer/sine_wave_generator.h"
    
    #include 
    #include 
    
    #include "rtc_base/numerics/safe_conversions.h"
    
    namespace webrtc {
    
    namespace {
    constexpr float kPi = 3.14159265f;
    }  // namespace
    
    void SineWaveGenerator::GenerateNextFrame(AudioFrame* frame) {
      RTC_DCHECK(frame);
      // 获取用来保存数据的指针地址(一段Buffer)
      int16_t* frame_data = frame->mutable_data();
      // samples_per_channel_ 表示每个声道采样多少个样本
      for (size_t i = 0; i < frame->samples_per_channel_; ++i) {
      	// 计算每个声道(Channel)的样本值
        for (size_t ch = 0; ch < frame->num_channels_; ++ch) {
         // 比如双声道(两个Channel),i = 0时就是frame_data[0] 和frame_data[1]
         // frame_data[ 2 * 0 + 0 ] --> Frame_data[0]
         // frame_data[ 2 * 0 + 1 ] --> Frame_data[1]
         // amplitude_  指振幅,sinf(phase_) 是对 phase_ 其sin函数值
          frame_data[frame->num_channels_ * i + ch] =
              rtc::saturated_cast<int16_t>(amplitude_ * sinf(phase_));
        }
    
    	// 这段是重点。 phase_ 就是正弦函数中的 变量值。
    	// wave_frequency_hz_  表示采样频率
    	// Kpi 为π
    	// 2∗ Kpi * wave_frequency_hz_ 是一个完整点的采样周期。
    	// frame->sample_rate_hz_ 这个参数表示采样率
    	// 采样率理解为在一个采样周期内,采多少个点。
        // 所以每个点的步长,例如 [ 0 0.1 0.2 ... 1.0 ], 0.1就是步长。
        // 采样的步长应为  采样周期 / 采样率。
        phase_ += wave_frequency_hz_ * 2 * kPi / frame->sample_rate_hz_;
      }
    }
    }  // namespace webrtc
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 上面的代码中,针对多通道、特定频率、特定采样率、特定时长(样本点),生成了一段正弦波数据。关于AudioFrame,实际上就是记录了一些设定项,以及保存数据的数组,其源码可以参考(webrtc/api/audio/audio_frame.h)
    • WebRTC中提供的Testsample
    // The audio level ranges linearly [0,32767].
    // audio_level 振幅
    // duration_ms 时间
    // sample_rate_hz 采样频率
    // num_channels 通道数
    std::unique_ptr<AudioFrame> CreateAudioFrame1kHzSineWave(int16_t audio_level,
                                                             int duration_ms,
                                                             int sample_rate_hz,
                                                             size_t num_channels) {
      // 根据采样频率,计算样本数
      size_t samples_per_channel = sample_rate_hz / (1000 / duration_ms);
      // 创建对象,保存样本数据
      std::vector<int16_t> audio_data(samples_per_channel * num_channels, 0);
      // 给audioFrame设置相关参数
      std::unique_ptr<AudioFrame> audio_frame = std::make_unique<AudioFrame>();
      audio_frame->UpdateFrame(0 /* RTP timestamp */, &audio_data[0],
                               samples_per_channel, sample_rate_hz,
                               AudioFrame::SpeechType::kNormalSpeech,
                               AudioFrame::VADActivity::kVadUnknown, num_channels);
    						   
      // 生成频率是1000(1kHZ)的正弦波
      SineWaveGenerator wave_generator(1000.0, audio_level);
      wave_generator.GenerateNextFrame(audio_frame.get());
      return audio_frame;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 需要注意一点,正弦波频率 和 采样频率不是一个事情。正弦波频率是指正弦波一秒钟震几下,在人耳辨别的范围内,频率越高越刺耳。采样频率指的是将连续信号转化为离散信号时,采样周期的选择,也就是一秒钟采几次(一般为44.1kHz)

    频谱分析

    • 利用一些音频软件,可以对生成的数据进行分析。比如通上述代码,生成300HZ的一段正弦波数据。通过频谱分析可以看出,其峰值为311。其误差值较小。
      在这里插入图片描述
  • 相关阅读:
    优化代码之使用策略模式(解决if..else..问题)
    python常用正则
    一、基本remix环境及HelloWord contract《2022 solidity8.+ 版本教程到实战》
    2020年9月大学英语六级翻译
    linux一键启动长安链
    HybridCLR 使用流程记录
    js验证字符串是否是时间日期格式
    Elasticsearch:使用向量化和 FFI/madvise 加速 Lucene
    Vue基于django的超时代停车场管理系统python
    锂电池电源管理系统设计与实现(单片机)
  • 原文地址:https://blog.csdn.net/zxc024000/article/details/133610853