Add JUCE DSP module to Projucer project. Added a sonogram view of the output audio.
This commit is contained in:
@ -173,21 +173,6 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
|
||||
};
|
||||
m_spec_order_ed.ModuleOrderOrEnabledChangedCallback = [this]()
|
||||
{
|
||||
/*
|
||||
const auto& specord = processor.getStretchSource()->getSpectrumProcessOrder();
|
||||
for (int i = 0; i < specord.size(); ++i)
|
||||
{
|
||||
int grtofind = specord[i].m_index;
|
||||
for (int j = 0; j < m_parcomps.size(); ++j)
|
||||
{
|
||||
int gid = m_parcomps[j]->m_group_id;
|
||||
if (gid == grtofind)
|
||||
{
|
||||
m_parcomps[j]->setEnabled(specord[i].m_enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
processor.setDirty();
|
||||
};
|
||||
|
||||
@ -244,8 +229,9 @@ PaulstretchpluginAudioProcessorEditor::PaulstretchpluginAudioProcessorEditor(Pau
|
||||
m_wavefilter_tab.addTab("Waveform", Colours::white, m_wave_container, true);
|
||||
m_wavefilter_tab.addTab("Ratio mixer", Colours::white, &m_ratiomixeditor, false);
|
||||
m_wavefilter_tab.addTab("Free filter", Colours::white, &m_free_filter_component, false);
|
||||
|
||||
addAndMakeVisible(&m_wavefilter_tab);
|
||||
m_wavefilter_tab.addTab("Spectrum", Colours::white, &m_sonogram, false);
|
||||
|
||||
addAndMakeVisible(&m_wavefilter_tab);
|
||||
setSize (1200, 320+14*25);
|
||||
startTimer(1, 100);
|
||||
startTimer(2, 1000);
|
||||
|
@ -265,6 +265,122 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class SimpleFFTComponent : public Component,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
SimpleFFTComponent() :
|
||||
|
||||
forwardFFT(fftOrder),
|
||||
spectrogramImage(Image::RGB, 512, 512, true)
|
||||
{
|
||||
setOpaque(true);
|
||||
startTimerHz(60);
|
||||
|
||||
}
|
||||
|
||||
~SimpleFFTComponent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void addAudioBlock(const AudioBuffer<float>& bufferToFill)
|
||||
{
|
||||
if (bufferToFill.getNumChannels() > 0)
|
||||
{
|
||||
const auto* channelData = bufferToFill.getReadPointer(0);
|
||||
|
||||
for (auto i = 0; i < bufferToFill.getNumSamples(); ++i)
|
||||
pushNextSampleIntoFifo(channelData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
spectrogramImage = Image(Image::RGB, getWidth(), getHeight(), true);
|
||||
}
|
||||
|
||||
void paint(Graphics& g) override
|
||||
{
|
||||
g.fillAll(Colours::black);
|
||||
|
||||
g.setOpacity(1.0f);
|
||||
g.drawImage(spectrogramImage, getLocalBounds().toFloat());
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
if (nextFFTBlockReady)
|
||||
{
|
||||
drawNextLineOfSpectrogram();
|
||||
nextFFTBlockReady = false;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void pushNextSampleIntoFifo(float sample) noexcept
|
||||
{
|
||||
// if the fifo contains enough data, set a flag to say
|
||||
// that the next line should now be rendered..
|
||||
if (fifoIndex == fftSize)
|
||||
{
|
||||
if (!nextFFTBlockReady)
|
||||
{
|
||||
zeromem(fftData, sizeof(fftData));
|
||||
memcpy(fftData, fifo, sizeof(fifo));
|
||||
nextFFTBlockReady = true;
|
||||
}
|
||||
|
||||
fifoIndex = 0;
|
||||
}
|
||||
|
||||
fifo[fifoIndex++] = sample;
|
||||
}
|
||||
|
||||
void drawNextLineOfSpectrogram()
|
||||
{
|
||||
auto rightHandEdge = spectrogramImage.getWidth() - 1;
|
||||
auto imageHeight = spectrogramImage.getHeight();
|
||||
|
||||
// first, shuffle our image leftwards by 1 pixel..
|
||||
spectrogramImage.moveImageSection(0, 0, 1, 0, rightHandEdge, imageHeight);
|
||||
|
||||
// then render our FFT data..
|
||||
forwardFFT.performFrequencyOnlyForwardTransform(fftData);
|
||||
|
||||
// find the range of values produced, so we can scale our rendering to
|
||||
// show up the detail clearly
|
||||
auto maxLevel = FloatVectorOperations::findMinAndMax(fftData, fftSize / 2);
|
||||
|
||||
for (auto y = 1; y < imageHeight; ++y)
|
||||
{
|
||||
auto skewedProportionY = 1.0f - std::exp(std::log(y / (float)imageHeight) * 0.2f);
|
||||
auto fftDataIndex = jlimit(0, fftSize / 2, (int)(skewedProportionY * fftSize / 2));
|
||||
auto level = jmap(fftData[fftDataIndex], 0.0f, jmax(maxLevel.getEnd(), 1e-5f), 0.0f, 1.0f);
|
||||
|
||||
spectrogramImage.setPixelAt(rightHandEdge, y, Colour::fromHSV(level, 1.0f, level, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
fftOrder = 10,
|
||||
fftSize = 1 << fftOrder
|
||||
};
|
||||
|
||||
private:
|
||||
dsp::FFT forwardFFT;
|
||||
Image spectrogramImage;
|
||||
|
||||
float fifo[fftSize];
|
||||
float fftData[8 * fftSize];
|
||||
int fifoIndex = 0;
|
||||
bool nextFFTBlockReady = false;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
class AudioFilePreviewComponent : public FilePreviewComponent
|
||||
{
|
||||
public:
|
||||
@ -319,7 +435,7 @@ public:
|
||||
void chooseFile();
|
||||
void showRenderDialog();
|
||||
void executeModalMenuAction(int menuid, int actionid);
|
||||
|
||||
SimpleFFTComponent m_sonogram;
|
||||
private:
|
||||
PaulstretchpluginAudioProcessor& processor;
|
||||
uptrvec<ParameterComponent> m_parcomps;
|
||||
@ -337,6 +453,7 @@ private:
|
||||
zoom_scrollbar m_zs;
|
||||
RatioMixerEditor m_ratiomixeditor{ 8 };
|
||||
FreeFilterComponent m_free_filter_component;
|
||||
|
||||
MyTabComponent m_wavefilter_tab;
|
||||
Component* m_wave_container=nullptr;
|
||||
void showAbout();
|
||||
|
@ -811,6 +811,11 @@ void PaulstretchpluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, M
|
||||
{
|
||||
buffer.clear();
|
||||
}
|
||||
auto ed = dynamic_cast<PaulstretchpluginAudioProcessorEditor*>(getActiveEditor());
|
||||
if (ed != nullptr)
|
||||
{
|
||||
ed->m_sonogram.addAudioBlock(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
Reference in New Issue
Block a user