Upload files to "Source"
This commit is contained in:
@@ -1,102 +1,102 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "AudioBufferQueue.h"
|
#include "AudioBufferQueue.h"
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
template <typename SampleType>
|
template <typename SampleType>
|
||||||
class ScopeComponent : public juce::Component,
|
class ScopeComponent : public juce::Component,
|
||||||
private juce::Timer
|
private juce::Timer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Queue = AudioBufferQueue<SampleType>;
|
using Queue = AudioBufferQueue<SampleType>;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
ScopeComponent(Queue& queueToUse)
|
ScopeComponent(Queue& queueToUse)
|
||||||
: audioBufferQueue(queueToUse)
|
: audioBufferQueue(queueToUse)
|
||||||
{
|
{
|
||||||
sampleData.fill(SampleType(0));
|
sampleData.fill(SampleType(0));
|
||||||
setFramesPerSecond(30);
|
setFramesPerSecond(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void setFramesPerSecond(int framesPerSecond)
|
void setFramesPerSecond(int framesPerSecond)
|
||||||
{
|
{
|
||||||
jassert(framesPerSecond > 0 && framesPerSecond < 1000);
|
jassert(framesPerSecond > 0 && framesPerSecond < 1000);
|
||||||
startTimerHz(framesPerSecond);
|
startTimerHz(framesPerSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void paint(juce::Graphics& g) override
|
void paint(juce::Graphics& g) override
|
||||||
{
|
{
|
||||||
g.fillAll(juce::Colours::black);
|
g.fillAll(juce::Colours::black);
|
||||||
g.setColour(juce::Colours::white);
|
g.setColour(juce::Colours::white);
|
||||||
|
|
||||||
auto area = getLocalBounds();
|
auto area = getLocalBounds();
|
||||||
auto h = (SampleType)area.getHeight();
|
auto h = (SampleType)area.getHeight();
|
||||||
auto w = (SampleType)area.getWidth();
|
auto w = (SampleType)area.getWidth();
|
||||||
|
|
||||||
// Oscilloscope
|
// Oscilloscope
|
||||||
auto scopeRect = juce::Rectangle<SampleType>{ SampleType(0), SampleType(0), w, h / 2 };
|
auto scopeRect = juce::Rectangle<SampleType>{ SampleType(0), SampleType(0), w, h / 2 };
|
||||||
plot(sampleData.data(), sampleData.size(), g, scopeRect, SampleType(1), h / 4);
|
plot(sampleData.data(), sampleData.size(), g, scopeRect, SampleType(1), h / 4);
|
||||||
|
|
||||||
// Spectrum
|
// Spectrum
|
||||||
auto spectrumRect = juce::Rectangle<SampleType>{ SampleType(0), h / 2, w, h / 2 };
|
auto spectrumRect = juce::Rectangle<SampleType>{ SampleType(0), h / 2, w, h / 2 };
|
||||||
plot(spectrumData.data(), spectrumData.size() / 4, g, spectrumRect);
|
plot(spectrumData.data(), spectrumData.size() / 4, g, spectrumRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void resized() override {}
|
void resized() override {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
Queue& audioBufferQueue;
|
Queue& audioBufferQueue;
|
||||||
std::array<SampleType, Queue::bufferSize> sampleData;
|
std::array<SampleType, Queue::bufferSize> sampleData;
|
||||||
|
|
||||||
juce::dsp::FFT fft{ Queue::order };
|
juce::dsp::FFT fft{ Queue::order };
|
||||||
using WindowFun = juce::dsp::WindowingFunction<SampleType>;
|
using WindowFun = juce::dsp::WindowingFunction<SampleType>;
|
||||||
WindowFun windowFun{ (size_t)fft.getSize(), WindowFun::hann };
|
WindowFun windowFun{ (size_t)fft.getSize(), WindowFun::hann };
|
||||||
std::array<SampleType, 2 * Queue::bufferSize> spectrumData;
|
std::array<SampleType, 2 * Queue::bufferSize> spectrumData;
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void timerCallback() override
|
void timerCallback() override
|
||||||
{
|
{
|
||||||
audioBufferQueue.pop(sampleData.data());
|
audioBufferQueue.pop(sampleData.data());
|
||||||
juce::FloatVectorOperations::copy(spectrumData.data(), sampleData.data(), (int)sampleData.size());
|
juce::FloatVectorOperations::copy(spectrumData.data(), sampleData.data(), (int)sampleData.size());
|
||||||
|
|
||||||
auto fftSize = (size_t)fft.getSize();
|
auto fftSize = (size_t)fft.getSize();
|
||||||
|
|
||||||
jassert(spectrumData.size() == 2 * fftSize);
|
jassert(spectrumData.size() == 2 * fftSize);
|
||||||
windowFun.multiplyWithWindowingTable(spectrumData.data(), fftSize);
|
windowFun.multiplyWithWindowingTable(spectrumData.data(), fftSize);
|
||||||
fft.performFrequencyOnlyForwardTransform(spectrumData.data());
|
fft.performFrequencyOnlyForwardTransform(spectrumData.data());
|
||||||
|
|
||||||
static constexpr auto mindB = SampleType(-160);
|
static constexpr auto mindB = SampleType(-160);
|
||||||
static constexpr auto maxdB = SampleType(0);
|
static constexpr auto maxdB = SampleType(0);
|
||||||
|
|
||||||
for (auto& s : spectrumData)
|
for (auto& s : spectrumData)
|
||||||
s = juce::jmap(juce::jlimit(mindB, maxdB, juce::Decibels::gainToDecibels(s) - juce::Decibels::gainToDecibels(SampleType(fftSize))), mindB, maxdB, SampleType(0), SampleType(1));
|
s = juce::jmap(juce::jlimit(mindB, maxdB, juce::Decibels::gainToDecibels(s) - juce::Decibels::gainToDecibels(SampleType(fftSize))), mindB, maxdB, SampleType(0), SampleType(1));
|
||||||
|
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
static void plot(const SampleType* data,
|
static void plot(const SampleType* data,
|
||||||
size_t numSamples,
|
size_t numSamples,
|
||||||
juce::Graphics& g,
|
juce::Graphics& g,
|
||||||
juce::Rectangle<SampleType> rect,
|
juce::Rectangle<SampleType> rect,
|
||||||
SampleType scaler = SampleType(1),
|
SampleType scaler = SampleType(1),
|
||||||
SampleType offset = SampleType(0))
|
SampleType offset = SampleType(0))
|
||||||
{
|
{
|
||||||
auto w = rect.getWidth();
|
auto w = rect.getWidth();
|
||||||
auto h = rect.getHeight();
|
auto h = rect.getHeight();
|
||||||
auto right = rect.getRight();
|
auto right = rect.getRight();
|
||||||
|
|
||||||
auto center = rect.getBottom() - offset;
|
auto center = rect.getBottom() - offset;
|
||||||
auto gain = h * scaler;
|
auto gain = h * scaler;
|
||||||
|
|
||||||
for (size_t i = 1; i < numSamples; ++i)
|
for (size_t i = 1; i < numSamples; ++i)
|
||||||
g.drawLine({ juce::jmap(SampleType(i - 1), SampleType(0), SampleType(numSamples - 1), SampleType(right - w), SampleType(right)),
|
g.drawLine({ juce::jmap(SampleType(i - 1), SampleType(0), SampleType(numSamples - 1), SampleType(right - w), SampleType(right)),
|
||||||
center - gain * data[i - 1],
|
center - gain * data[i - 1],
|
||||||
juce::jmap(SampleType(i), SampleType(0), SampleType(numSamples - 1), SampleType(right - w), SampleType(right)),
|
juce::jmap(SampleType(i), SampleType(0), SampleType(numSamples - 1), SampleType(right - w), SampleType(right)),
|
||||||
center - gain * data[i] });
|
center - gain * data[i] });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1,62 +1,62 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
template <typename SampleType>
|
template <typename SampleType>
|
||||||
class ScopeDataCollector
|
class ScopeDataCollector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
ScopeDataCollector(AudioBufferQueue<SampleType>& queueToUse)
|
ScopeDataCollector(AudioBufferQueue<SampleType>& queueToUse)
|
||||||
: audioBufferQueue(queueToUse)
|
: audioBufferQueue(queueToUse)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void process(const SampleType* data, size_t numSamples)
|
void process(const SampleType* data, size_t numSamples)
|
||||||
{
|
{
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
|
|
||||||
if (state == State::waitingForTrigger)
|
if (state == State::waitingForTrigger)
|
||||||
{
|
{
|
||||||
while (index++ < numSamples)
|
while (index++ < numSamples)
|
||||||
{
|
{
|
||||||
auto currentSample = *data++;
|
auto currentSample = *data++;
|
||||||
|
|
||||||
if (currentSample >= triggerLevel && prevSample < triggerLevel)
|
if (currentSample >= triggerLevel && prevSample < triggerLevel)
|
||||||
{
|
{
|
||||||
numCollected = 0;
|
numCollected = 0;
|
||||||
state = State::collecting;
|
state = State::collecting;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
prevSample = currentSample;
|
prevSample = currentSample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == State::collecting)
|
if (state == State::collecting)
|
||||||
{
|
{
|
||||||
while (index++ < numSamples)
|
while (index++ < numSamples)
|
||||||
{
|
{
|
||||||
buffer[numCollected++] = *data++;
|
buffer[numCollected++] = *data++;
|
||||||
|
|
||||||
if (numCollected == buffer.size())
|
if (numCollected == buffer.size())
|
||||||
{
|
{
|
||||||
audioBufferQueue.push(buffer.data(), buffer.size());
|
audioBufferQueue.push(buffer.data(), buffer.size());
|
||||||
state = State::waitingForTrigger;
|
state = State::waitingForTrigger;
|
||||||
prevSample = SampleType(100);
|
prevSample = SampleType(100);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
AudioBufferQueue<SampleType>& audioBufferQueue;
|
AudioBufferQueue<SampleType>& audioBufferQueue;
|
||||||
std::array<SampleType, AudioBufferQueue<SampleType>::bufferSize> buffer;
|
std::array<SampleType, AudioBufferQueue<SampleType>::bufferSize> buffer;
|
||||||
size_t numCollected;
|
size_t numCollected;
|
||||||
SampleType prevSample = SampleType(100);
|
SampleType prevSample = SampleType(100);
|
||||||
|
|
||||||
static constexpr auto triggerLevel = SampleType(0.05);
|
static constexpr auto triggerLevel = SampleType(0.05);
|
||||||
|
|
||||||
enum class State { waitingForTrigger, collecting } state{ State::waitingForTrigger };
|
enum class State { waitingForTrigger, collecting } state{ State::waitingForTrigger };
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user