JUCE学习笔记07——自定义正弦振荡器类
一、变量:
频率、采样率、当前角度/相位、角度/相位增量、样本值(振幅)
频率(frequency):
每秒完整周期的次数
采样率(sampleRate):
每秒的采样数
采样值(currentSample):
当前采样点的振幅——音频系统最终实现声音输出的数据
当前角度/相位(currentAngle):
当前采样点在周期内的位置
角度/相位增量(angleDelta):
下个采样点与当前采样点之间的角度/相位增量
二、公式:
1.frequency/sampleRate:
单个采样数与一个周期采样数的比率
2.angleDelta=(frequency/sampleRate)*2pi:
相邻采样点之间的角度/相位差(一个周期为2pi)
3.currentAngle=currentAngle+angleDelta
当前角度/相位与角度/相位增量的和为下一个样本的角度/相位
4.currentSample=sin(currentAngle)
当前样本的角度/相位计算正弦值
三、实现:
创建正弦振荡器类
1.成员函数setFrequency()设置波形频率,计算相邻样本间的角度/相位差
private:
float angleDelta; //角度/相位增量
float currentAngle; //存储当前角度
void SinWave::setFrequency(float freq, float sampleRate)
{
angleDelta = (freq*MathConstants<float>::twoPi) / sampleRate;
}
2.函数updateAngle()更新当前角度/相位
void SinWaveOsc::updateAngle()
{
currentAngle += angleDelda;//当前角度+增量获取新角度
if (currentAngle >= MathConstants<float>::twoPi)
currentAngle -= MathConstants<float>::twoPi;//限制角度在2Π内
}
3.getNextSample()函数计算波形采样点的振幅值
float SinWaveOsc::getNextSample()
{
auto currentSample = sin(currentAngle);
updateAngle();
return currentSample;
}
SinWaveOsc类完整代码:
//SinWaveOsc.h
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
class SinWaveOsc {
public:
//==============================================
SinWaveOsc();
~SinWaveOsc();
//==============================================
void setFrequancy(float freq, float sampleRate);
float getNextSample();
void updateAngle();
private:
float currentAngle;
float angleDelda;
};
//SinWaveOsc.cpp
#include "SinWaveOsc.h"
//========================================================================
SinWaveOsc::SinWaveOsc()
{
currentAngle = 0.0f;
angleDelda = 0.0f;
}
SinWaveOsc::~SinWaveOsc()
{
}
//========================================================================
void SinWaveOsc::setFrequancy(float freq,float sampleRate)
{
angleDelda = freq / sampleRate * MathConstants<float>::twoPi;
}
float SinWaveOsc::getNextSample()
{
auto currentSample = sin(currentAngle);
updateAngle();
return currentSample;
}
void SinWaveOsc::updateAngle()
{
currentAngle += angleDelda;
if (currentAngle >= MathConstants<float>::twoPi)
currentAngle -= MathConstants<float>::twoPi;
}
创建正弦振荡器对象在主组件中实现声音播放
//MainComponent.h
#include "../JuceLibraryCode/JuceHeader.h"
#include "SinWaveOsc.h"
//==============================================================================
class MainComponent : public AudioAppComponent
{
public:
//==============================================================================
MainComponent();
~MainComponent();
//==============================================================================
void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override;
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override;
void releaseResources() override;
//==============================================================================
void paint (Graphics& g) override;
void resized() override;
private:
//==============================================================================
SinWaveOsc sinWaveOsc;
float level;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
//MainComponent.cpp
#include "MainComponent.h"
//==============================================================================
MainComponent::MainComponent()
{
setSize (600, 100);
if (RuntimePermissions::isRequired (RuntimePermissions::recordAudio)
&& ! RuntimePermissions::isGranted (RuntimePermissions::recordAudio))
{
RuntimePermissions::request (RuntimePermissions::recordAudio,
[&] (bool granted) { if (granted) setAudioChannels (2, 2); });
}
else
{
setAudioChannels (0, 2);
}
}
MainComponent::~MainComponent()
{
shutdownAudio();
}
//==============================================================================
void MainComponent::prepareToPlay (int samplesPerBlockExpected, double sampleRate)
{
sinWaveOsc.setFrequancy(220, sampleRate);
level = 0.1f; //控制振幅(音量)
}
void MainComponent::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill)
{
auto* leftChannel = bufferToFill.buffer->getWritePointer(0, bufferToFill.startSample);
auto* rightChannel = bufferToFill.buffer->getWritePointer(1, bufferToFill.startSample);
bufferToFill.clearActiveBufferRegion();
for (int sample = 0; sample < bufferToFill.numSamples; ++sample)
{
leftChannel[sample] = sinWaveOsc.getNextSample()*level;
rightChannel[sample] = sinWaveOsc.getNextSample()*level;
}
}
void MainComponent::releaseResources()
{
}
//==============================================================================
void MainComponent::paint (Graphics& g)
{
}
void MainComponent::resized()
{
}