Timur's Oscilloscope

Hi Timur, 

Finally I made your oscilloscope work with my project.

Haven't finished yet but here is how it looks.

I had to change the value of bufferYscale because it was a little too much and it passed the bounds of it's own component.

yes

1 Like

Nice work. Would you consider sharing your oscilloscope code changes with us?

Of course man...that is your code. ;)

I just changed the bufferYScale value, the color and the PathStrokeType. :P

Here you have the code :


/*
  ==============================================================================
    Oscilloscope.h
    Created: 26 Jan 2016 1:06:47am
    Author:  Geri
  ==============================================================================
*/
#ifndef OSCILLOSCOPE_H_INCLUDED
#define OSCILLOSCOPE_H_INCLUDED
#include <array>
class Oscilloscope : public Component, private Timer
{
public:
    //==========================================================================
    Oscilloscope()
        : writePos(0)
    {
        startTimer(60);
    }
    //==========================================================================
    void pushBuffer(const float* data, int numSamples)
    {
        for (int i = 0; i < numSamples; ++i)
            buffer[++writePos % buffer.size()] = data[i];
    }
    //==========================================================================
    void paint(Graphics& g) override
    {
        g.fillAll(Colours::black.brighter(0.22f));
        Rectangle<int> r = getLocalBounds();
        Path path;
        path.startNewSubPath(0, 0.5 * r.getHeight());
        const float bufferYscale = 1.0f;
        int paintPos = 2;
        while (paintPos < buffer.size())
        {
            if (isZeroCrossing(paintPos))
                break;
            ++paintPos;
        }
        const int posOffset = paintPos;
        while (paintPos < buffer.size())
        {
            Point<float> p((paintPos - posOffset) * r.getWidth() / paintSize,
                0.5 * ((bufferYscale * buffer[paintPos]) + 1) * r.getHeight());
            
            path.lineTo(p);
            ++paintPos;
        }
        g.setColour(Colour(0, 102, 204));
        g.strokePath(path, PathStrokeType(1.5f));
    }
private:
    //==========================================================================
    void timerCallback() override
    {
        repaint();
    }
    bool isZeroCrossing(int i) const noexcept
    {
        jassert(i > 0);
        return buffer[i] > buffer[i - 1] && buffer[i] > 0 && buffer[i - 1] < 0;
    }
    //==========================================================================
    std::array<float, 1024> buffer;
    std::size_t writePos;
    const int bufferSize = 16384;
    const int paintSize = 256;
};


#endif  // OSCILLOSCOPE_H_INCLUDED

In the beginning the bufferYscale was = 3.0f and I just changed it to 1.0f and the path didn't pass the local bounds anymore.

 

 

I have a similar oscilloascope code but I was wondering, what's the best way of pushing the samples to the oscilloscope buffer in a plugin?
Sinche the oscilloscope will be in the Editor, should I pass a pointer to the oscilloscope to the Processor?

The proper way would be to use a lock-free fifo to push the samples from the audio thread into the buffer of the Oscilloscope.

The easiest way to achieve this is to have a reasonably large buffer in the oscilloscope, and then if you render a waveform from the buffer on the GUI thread you should have some means of making sure that you never read from the buffer region the audio thread is currently writing to (otherwise you are entering undefined behaviour land).