-
Notifications
You must be signed in to change notification settings - Fork 32
Expand file tree
/
Copy pathSpectroscopeComponent.cpp
More file actions
131 lines (107 loc) · 4.27 KB
/
Copy pathSpectroscopeComponent.cpp
File metadata and controls
131 lines (107 loc) · 4.27 KB
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
==============================================================================
SpectroscopeComponent.cpp
Created: 8 Apr 2017 12:46:51pm
Author: Nick Thompson
==============================================================================
*/
#include "../JuceLibraryCode/JuceHeader.h"
#include "SpectroscopeComponent.h"
//==============================================================================
SpectroscopeComponent::SpectroscopeComponent()
: m_fifoIndex(0),
m_fftBlockReady(false),
m_forwardFFT(kFFTOrder),
m_window(kFFTSize, juce::dsp::WindowingFunction<float>::hann),
m_strokeColour(Colours::white),
m_fillStartColour(Colours::white.withAlpha(0.2f)),
m_fillStopColour(Colours::white.withAlpha(0.8f))
{
zeromem(m_outputData, sizeof(m_outputData));
setSize(700, 200);
startTimerHz(30);
}
SpectroscopeComponent::~SpectroscopeComponent()
{
stopTimer();
}
void SpectroscopeComponent::paint (Graphics& g)
{
const float width = (float) getWidth();
const float height = (float) getHeight();
// Clear the drawing target
g.setColour(Colours::transparentBlack);
g.fillAll();
// The values in the output bins after the FFT have a range that I don't understand
// and isn't explained in the docs. It seems that if I scale down by the size of the
// fft buffer, I get somewhat reasonable results on the graph. But in examples I've
// seen, we would just divide here by the maximum value in the bins at the time of
// drawing. Seeing as that would be inconsistent between frames, I'm defaulting to the
// size of the fft here unless the max value in the bins is larger.
Range<float> maxBin = FloatVectorOperations::findMinAndMax(m_outputData, kOutputSize);
const float scale = 1.0f / jmax((float) kFFTSize, maxBin.getEnd());
g.setColour(m_fillStartColour);
for (int i = 0; i < kOutputSize; ++i)
{
float x = std::log10 (1 + 39 * ((i + 1.0f) / kOutputSize)) / std::log10 (40.0f) * width;
const float yMag = scale * m_outputData[i];
const float yDecibel = Decibels::gainToDecibels(yMag);
const float y = jmap(yDecibel, -90.0f, -12.0f, height, 0.0f);
g.drawVerticalLine((int) x, y, height);
}
}
void SpectroscopeComponent::resized()
{
}
void SpectroscopeComponent::timerCallback()
{
if (m_fftBlockReady)
{
// Compute the frequency transform
m_window.multiplyWithWindowingTable(m_fftData, kFFTSize);
m_forwardFFT.performFrequencyOnlyForwardTransform(m_fftData);
// Copy the frequency bins into the output data buffer, taking
// max(output[i], fftData[i]) for each bin. Note that after computing the
// FrequencyOnlyForwardTransform on an array A of size N, A[N/2, N) is full
// of zeros, and A[0, N/4) is a mirror of A[N/4, N/2). Therefore we only copy
// kFFTSize / 2 samples into the output data buffer here.
FloatVectorOperations::max(m_outputData, m_outputData, m_fftData, kOutputSize);
m_fftBlockReady = false;
}
// Decay the output bin magnitudes
for (int i = 0; i < kOutputSize; ++i)
m_outputData[i] *= 0.707f;
repaint();
}
void SpectroscopeComponent::pushBuffer(AudioSampleBuffer &buffer)
{
if (buffer.getNumChannels() > 0)
{
const int numSamples = buffer.getNumSamples();
const float* channelData = buffer.getReadPointer(0);
for (int i = 0; i < numSamples; ++i)
pushSample(channelData[i]);
}
}
inline void SpectroscopeComponent::pushSample(float sample)
{
// When we wrap around the fifo table, we copy the data into the
// FFT buffer and prepare to perform the transform.
if (m_fifoIndex == kFFTSize)
{
if (!m_fftBlockReady)
{
zeromem(m_fftData, sizeof(m_fftData));
memcpy(m_fftData, m_fifo, sizeof(m_fifo));
m_fftBlockReady = true;
}
m_fifoIndex = 0;
}
m_fifo[m_fifoIndex++] = sample;
}
void SpectroscopeComponent::setColours(Colour strokeColour, Colour fillStartColour, Colour fillStopColour)
{
m_strokeColour = strokeColour;
m_fillStartColour = fillStartColour;
m_fillStopColour = fillStopColour;
}