I want to share my tools for making meters with you!


#1

Hey everyone!

I'm still fairly new to JUCE, but I've been working a lot on making an easy reusable way to create 

meters.  Here's what I've come up with.

Filmstrip Maker

A simple command line tool I made with opencv that lets you stitch several images together into a filmstrip.

I couldnt find anything that did this the way i wanted so I decided to make it myself.  This lets you export each individual

frame from your image editor and then make the filmstrip easily. It is still very basic and needs some work.

(if you know opencv and want to contribute please do!)

Here's the source code:

https://github.com/abaga129/FilmstripMaker

And heres the windows executable (64bit)

https://www.dropbox.com/s/4ypkbelxrap13fm/FilmstripMaker.exe?dl=0

 

Filmstrip Meter

I put together a JUCE class that uses the images from Filmstrip Maker to create a meter.

I'm pretty happy with this so far, but if you want to improve it, please feel free to.

Here's the source code:

https://github.com/abaga129/FilmstripMeter

 

I still have some work to do on these projects. Right now the Filmstrip Meter class is really

only for volume meters. I plan to extend it to gain reduction meters as well.

Also the Filmstrip Maker program has one issue I've noticed. If the input image has transparent parts, the

transparent parts will appear white in the output image.

 

I hope someone finds this code useful or atleast educational!

Thanks,

-Ethan


#2

Thanks for sharing.

I think this should really go in the Useful Tools and Components section as it can apply not only to plugins but other types of apps. 


#3

If you only take samples at regular intervals from the stream you don't have a very accurate meter.  A 100Hz waveform, for example, being sampled approximately every 10ms might behave very strangely as you sample the waveform at the same period each time. 

You might be better off looking at AbstractFIFO and streaming the whole audio into your GUI thread for processing, or having some peak detection code in the audio thread? 


#4

Can I just ask how you approach grabbing the values from the FIFO ? 

 

Do you wake up the GUI / Worker thread acting as the FIFO consumer with some sort of change notification of do you poll the queue in a timer still ? 

 

Been looking into this topic recently. 

 

Cheers


#5

I run a timer in my meter class to pull the latest data.   Theres' no change notification.


#6

I thought I'd posted some of the code somewhere, but buggered if I can find it now !!  If I get a chance I'll pop some stuff up.  It's kinda cute, it's got a queue manager that handles named queues and a few other bits..

 


/*
  ==============================================================================
    audio_stream_fifo.h
    Created: 27 Jan 2014 8:14:20pm
    Author:  Jim Credland
  ==============================================================================
*/
#ifndef AUDIO_STREAM_FIFO_H_INCLUDED
#define AUDIO_STREAM_FIFO_H_INCLUDED

/**
 AudioStreamFifo objects typically take a non-stop stream of
 audio from the processor thread another thread, e.g. the GUI.
 Used for driving complex metering, scopes and so on.
 Other than during instantiation there is no locking on the
 sending thread.
 It uses twice as much memory as the buffer size and gains
 a little performance as a result. */


class AudioStreamFifo
{
public:
    AudioStreamFifo (const String& name, int buffer_size) :
        fullQueueCount(0),
        myName (name),
        fifo (buffer_size)
    {
        fifodata = new char[buffer_size * 2];
    }
    const String& getName()
    {
        return myName;
    }
    ~AudioStreamFifo()
    {
        // TODO: replace with heapblock
        delete[] fifodata;
    }
    struct BlockDescription
    {
        int channels;
        int samples;
    };
    /** Copies an audio buffer into the fifo */
    void send (AudioSampleBuffer& buffer);
    /** Returns a buffer for processing. This must be deleted by
     the caller after use.
     A more efficent routine would provide pointers to the data in the fifo
     and let you flag when you'd finished with it.
     Returns a nullptr if there's no data.
     
     NOTE: Call Next after you've finished processing the block. */
    AudioSampleBuffer* receive();
    /** Call next after processing each block. */
    void next()
    {
        fifo.finishedRead (lastReceiveSize);
    }
private:
    int fullQueueCount;
    int lastReceiveSize;
    String myName;
    AbstractFifo fifo;
    char* fifodata;
    JUCE_LEAK_DETECTOR (AudioStreamFifo)
};
class AudioStreamSourceManager
{
public:
    void registerStream (AudioStreamFifo& stream)
    {
        // you should only be registering a stream once
        // and they should have unique names.
        jassert (streams.find (stream.getName()) == streams.end());
        streams[stream.getName()] = &stream;
    }
    AudioStreamFifo* get (const String& name)
    {
        // the stream wasn't found - is the name right? did you register it?
        jassert (streams.find (name) != streams.end());
        return streams[name];
    }
private:
    std::map<String, AudioStreamFifo*> streams;
};
/**
 The audio stream manager is part of the GUI.  It's called with the
 processor parameter store, which is used to identify any audio stream
 FIFOs that are available from the processor.
 These can be selected by name and components can subscribe to
 recieve a constant stream of audio.
 Once all the threads have been passed the audio data buffer the data
 is released from the FIFO.
 */
class AudioStreamListenerManager
:
public Timer
{
public:
    AudioStreamListenerManager (AudioStreamSourceManager& src) :
        source (src)
    {}
    ~AudioStreamListenerManager()
    {
        stopTimer();
    }
    void callListeners();
    void timerCallback() { callListeners(); }
    class StreamListener
    {
    public:
        virtual ~StreamListener() {}
        virtual void processBlock (const String& name,
                                   AudioSampleBuffer* b) = 0;
    };
    void registerStreamListener (const String& name,
                                 StreamListener& listener);
private:
    struct Stream
    {
        AudioStreamFifo* fifo;
        std::vector<StreamListener*> listeners;
        String name;
    };
    std::vector<Stream> streams;
    AudioStreamSourceManager& source;
};



#endif  // AUDIO_STREAM_FIFO_H_INCLUDED


#7

Thanks for the feedback bazrush. I'll definitely look into that when I get a chance. I posted this and then got busy so I kinda disappeared. But I definitely see what you mean with potentially weird behavior from the meter.  I also made the FilmstripMaker cross platform as suggested by adamski. So you should be able to compile it on OS X and Linux as well.

I'm going to try and extend the class to work for gain reduction meters too.

If anyone has suggestions please let me know or open an issue on github!