Code

CMake Commands

Before running this code, clone JUCE at ~/JUCE6

cmake -B cmake-build-install -DCMAKE_INSTALL_PREFIX=~/JUCE6
cmake -B cmake-build -DCMAKE_PREFIX_PATH=~/JUCE6/ -DCMAKE_BUILD_TYPE=Debug
lldb gensrc/cmake-build/GuiAppExample_artefacts/Debug/Gui\ App\ Example.app/Contents/MacOS/Gui\ App\ Example

CMakeLists.txt

In this project I include all juce modules. The snippet is taken from Demo Runner file

set(CMAKE_VERBOSE_MAKEFILE ON)
cmake_minimum_required(VERSION 3.15)
project(GUI_APP_EXAMPLE VERSION 0.0.1)

find_package(JUCE CONFIG REQUIRED)        # If you've installed JUCE to your system

juce_add_gui_app(GuiAppExample
    PRODUCT_NAME "Gui App Example")

target_sources(GuiAppExample
    PRIVATE
        Main.cpp
        MainComponent.cpp)

target_compile_definitions(GuiAppExample
    PRIVATE
        JUCE_WEB_BROWSER=0
        JUCE_USE_CURL=0
        JUCE_APPLICATION_NAME_STRING="$<TARGET_PROPERTY:GuiAppExample,JUCE_PRODUCT_NAME>"
        JUCE_APPLICATION_VERSION_STRING="$<TARGET_PROPERTY:GuiAppExample,JUCE_VERSION>")

target_link_libraries(GuiAppExample
    PRIVATE
        # GuiAppData            # If we'd created a binary data target, we'd link to it here
        juce::juce_gui_extra
        juce::juce_analytics
        juce::juce_audio_utils
        juce::juce_box2d
        juce::juce_dsp
        juce::juce_opengl
        juce::juce_osc
        juce::juce_product_unlocking
        juce::juce_video

    PUBLIC
        juce::juce_recommended_config_flags
        juce::juce_recommended_lto_flags
        juce::juce_recommended_warning_flags)

build.sh

#!/bin/sh
cmake -B cmake-build -DCMAKE_PREFIX_PATH=~/JUCE6/ -DCMAKE_BUILD_TYPE=Debug

MainComponent.h

This the the interface of our main component

#pragma once

#include "DemoUtilities.h"
#include <string>

class MainComponent  : public AudioAppComponent,
    public FilenameComponentListener,
    public CodeDocument::Listener,
    public Timer,
    public ChangeBroadcaster {

    private:
        int time;
        bool started = false;
        TextEditor label;
        Slider* bpm;
        CodeDocument codeDocument;
        std::unique_ptr<CodeEditorComponent> editor;
        TextEditor outputDisplay;

        FilenameComponent fileChooser { "File", {}, false, false, false, "*.wav", {}, "Select a sample"};

        MixerAudioSource * mixer;
        std::vector<AudioTransportSource *> transportSource;
        AudioFormatManager formatManager;

        TextButton startStopMain { "Start Transport / Stop Transport" };

    public:
        MainComponent();
        ~MainComponent() override;

        bool loadAudioResource (File resource);
        void prepareToPlay (int samplesPerBlockExpected, double sampleRate) override;
        void getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) override;
        void releaseResources() override;
        void runScript();
        void play (int sample);
        void paint (Graphics& g) override;
        void resized() override;
        void codeDocumentTextInserted (const String&, int) override;
        void codeDocumentTextDeleted (int, int) override;
        void startOrStopTimer();
        void timerCallback() override;
        void filenameComponentChanged (FilenameComponent*) override;


        struct SamplePlayer  : public DynamicObject {
            SamplePlayer (MainComponent& main) : owner (main)
            {
                setMethod ("play", play);
                setMethod ("time", time);
            }

            static Identifier getClassName()    { return "SamplePlayer"; }

            static var play (const var::NativeFunctionArgs& args)
            {
                if (args.numArguments > 0)
                    if (auto* thisObject = dynamic_cast<SamplePlayer*> (args.thisObject.getObject()))
                        thisObject->owner.play(int(args.arguments[0]));

                return var::undefined();
            }

            static var time (const var::NativeFunctionArgs& args)
            {
                auto* thisObject = dynamic_cast<SamplePlayer*> (args.thisObject.getObject());
                return var(thisObject->owner.time);
            }

            MainComponent& owner;

            JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SamplePlayer)
        };


        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

MainComponent.cpp

This code is taken from Sample Player, GUI example and JS example from juce codebase

#include "MainComponent.h"


MainComponent::MainComponent() {
    setOpaque (true);

    bpm = new Slider();
    bpm->setSliderStyle (Slider::Rotary);
    bpm->setRotaryParameters (MathConstants<int>::pi * 1.2f, MathConstants<float>::pi * 2.8f, false);
    bpm->setTextBoxStyle (Slider::TextBoxRight, true, 120, 64);
    bpm->setTextValueSuffix (" bpm");
    bpm->setRange(0.0, 360.0, 1.0);
    addAndMakeVisible (bpm);

    addAndMakeVisible (fileChooser);
    fileChooser.addListener (this);

    editor.reset (new CodeEditorComponent (codeDocument, nullptr));
    addAndMakeVisible (editor.get());
    editor->setFont ({ Font::getDefaultMonospacedFontName(), 14.0f, Font::plain });
    editor->setTabSize (4, true);
    editor->loadContent (
            "var tick = (SamplePlayer.time() % 16);\n"
            " var p1 = [1,0,0,0,1,0,0,0,1,0,0,0, 1,0,0,0];\n"
            " var p2 = [0,0,0,0,1,0,0,0,0,0,0,0, 1,0,0,0];\n"
            " var isHit1 = p1[tick];\n"
            " var isHit2 = p2[tick];\n"
            "if (isHit1) {\n"
            "    SamplePlayer.play(0);\n"
            "}\n"
            "if (isHit2) {\n"
            "    SamplePlayer.play(1);\n"
            "}\n"
            );

    label.setReadOnly (true);
    addAndMakeVisible (label);

    outputDisplay.setMultiLine (true);
    outputDisplay.setReadOnly (true);
    outputDisplay.setCaretVisible (false);
    outputDisplay.setFont ({ Font::getDefaultMonospacedFontName(), 14.0f, Font::plain });
    addAndMakeVisible (outputDisplay);

    codeDocument.addListener(this);

    formatManager.registerBasicFormats();
    mixer = new MixerAudioSource();

    addAndMakeVisible (startStopMain);

    startStopMain.onClick = [this] { startOrStopTimer(); };

    setSize (1024, 768);
    setAudioChannels (0, 2);
    time = 0;

}

MainComponent::~MainComponent() {
    fileChooser.removeListener (this);
    shutdownAudio();
}


bool MainComponent::loadAudioResource (File resource) {
    auto source = new AudioTransportSource();
    transportSource.push_back(source);

    source->stop();
    source->setSource(nullptr);
    AudioFormatReader* reader = nullptr;
    reader = formatManager.createReaderFor(resource);

    if (reader != nullptr) {
        auto numSamples = static_cast<int>(reader->lengthInSamples);
        source->setSource(new AudioFormatReaderSource (reader, true),
                0,
                nullptr,
                reader->sampleRate);
        mixer->addInputSource(source, true);
        return true;
    } else {
        return false;
    }
}

void MainComponent::prepareToPlay (int samplesPerBlockExpected, double sampleRate) {
    mixer->prepareToPlay (samplesPerBlockExpected, sampleRate);
}

void MainComponent::getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill) {
    if (started) {
        mixer->getNextAudioBlock(bufferToFill);
    }

}
void MainComponent::releaseResources() {
    mixer->releaseResources();
}

void MainComponent::runScript() {
    outputDisplay.clear();

    JavascriptEngine engine;
    engine.maximumExecutionTime = RelativeTime::seconds (5);
    engine.registerNativeObject ("SamplePlayer", new SamplePlayer (*this));

    auto startTime = Time::getMillisecondCounterHiRes();
    auto result = engine.execute (codeDocument.getAllContent());
    auto elapsedMs = Time::getMillisecondCounterHiRes() - startTime;

    if (result.failed())
        outputDisplay.setText (result.getErrorMessage());
    else
        outputDisplay.insertTextAtCaret ("\n(Execution time: " + String (elapsedMs, 2) + " milliseconds)");
}

void MainComponent::play (int sample) {
        transportSource[sample]->setPosition (0);
        transportSource[sample]->start();

        /*
    if (transportSource[sample]->isPlaying()) {
        // transportSource[sample]->stop();
    } else {
    }
    */
}

void MainComponent::paint (Graphics& g) {
        g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));

}

void MainComponent::resized() {
    auto area = getLocalBounds();

    using Track = juce::Grid::TrackInfo;
    using Fr = juce::Grid::Fr;

    juce::Grid grid;
    juce::Grid headerGrid;


    headerGrid.columnGap = 20_px;

    headerGrid.templateColumns= { Track (Fr (4)), Track (Fr (1)), Track (Fr (2)),  Track (Fr (4)) };
    headerGrid.templateRows = { Track (Fr (1))};

    headerGrid.items = { juce::GridItem(bpm), juce::GridItem(label), juce::GridItem (fileChooser), juce::GridItem (startStopMain)  };

    headerGrid.performLayout(area.removeFromTop(120));

    grid.templateColumns= { Track (Fr (1)) };
    grid.templateRows = { Track (Fr (1)), Track (Fr (10))};

    grid.items = { juce::GridItem (outputDisplay), juce::GridItem (*editor) };

    grid.performLayout (area);

}

void MainComponent::codeDocumentTextInserted (const String&, int) { }
void MainComponent::codeDocumentTextDeleted (int, int) {  }

void MainComponent::startOrStopTimer() {
    started = true;
    int current_bpm = int(bpm->getValue());
    float time_per_beat = (60.0 / current_bpm) * 4;
    int time_per_tick = (time_per_beat * 1000) / 16;
    startTimer(time_per_tick);
}

void MainComponent::timerCallback() {
    time += 1;
    label.clear();
    label.setText (std::to_string(time));
    // stopTimer();
    runScript();
}

void MainComponent::filenameComponentChanged (FilenameComponent*) {
    auto file = fileChooser.getCurrentFile();
    if (loadAudioResource(file)) {
        // std::cout << file;
        std::cout << "Loaded";
    }
}

Main.cpp

#include "MainComponent.h"

class GuiAppApplication  : public juce::JUCEApplication
{
public:
    GuiAppApplication() {}

    const juce::String getApplicationName() override       { return JUCE_APPLICATION_NAME_STRING; }
    const juce::String getApplicationVersion() override    { return JUCE_APPLICATION_VERSION_STRING; }
    bool moreThanOneInstanceAllowed() override             { return true; }

    void initialise (const juce::String& commandLine) override
    {
        juce::ignoreUnused (commandLine);
        mainWindow.reset (new MainWindow (getApplicationName()));
    }

    void shutdown() override
    {
        mainWindow = nullptr; // (deletes our window)
    }

    //==============================================================================
    void systemRequestedQuit() override
    {
        quit();
    }

    void anotherInstanceStarted (const juce::String& commandLine) override
    {
        juce::ignoreUnused (commandLine);
    }

    class MainWindow    : public juce::DocumentWindow
    {
    public:
        explicit MainWindow (juce::String name)
            : DocumentWindow (name,
                              juce::Desktop::getInstance().getDefaultLookAndFeel()
                                                          .findColour (ResizableWindow::backgroundColourId),
                              DocumentWindow::allButtons)
        {
            setUsingNativeTitleBar (true);
            setContentOwned (new MainComponent(), true);

           #if JUCE_IOS || JUCE_ANDROID
            setFullScreen (true);
           #else
            setResizable (true, true);
            centreWithSize (getWidth(), getHeight());
           #endif

            setVisible (true);
        }

        void closeButtonPressed() override
        {
            JUCEApplication::getInstance()->systemRequestedQuit();
        }


    private:
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
    };

private:
    std::unique_ptr<MainWindow> mainWindow;
};

//==============================================================================
// This macro generates the main() routine that launches the app.
START_JUCE_APPLICATION (GuiAppApplication)

DemoUtilities.h

#ifndef PIP_DEMO_UTILITIES_INCLUDED
#define PIP_DEMO_UTILITIES_INCLUDED 1

#include "JuceHeader.h"

//==============================================================================
/*
    This file contains a bunch of miscellaneous utilities that are
    used by the various demos.
*/

//==============================================================================
inline Colour getRandomColour (float brightness) noexcept
{
    return Colour::fromHSV (Random::getSystemRandom().nextFloat(), 0.5f, brightness, 1.0f);
}

inline Colour getRandomBrightColour() noexcept  { return getRandomColour (0.8f); }
inline Colour getRandomDarkColour() noexcept    { return getRandomColour (0.3f); }

inline Colour getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour uiColour, Colour fallback = Colour (0xff4d4d4d)) noexcept
{
    if (auto* v4 = dynamic_cast<LookAndFeel_V4*> (&LookAndFeel::getDefaultLookAndFeel()))
        return v4->getCurrentColourScheme().getUIColour (uiColour);

    return fallback;
}

inline File getExamplesDirectory() noexcept
{
   #ifdef PIP_JUCE_EXAMPLES_DIRECTORY
    MemoryOutputStream mo;

    auto success = Base64::convertFromBase64 (mo, JUCE_STRINGIFY (PIP_JUCE_EXAMPLES_DIRECTORY));
    ignoreUnused (success);
    jassert (success);

    return mo.toString();
   #elif defined PIP_JUCE_EXAMPLES_DIRECTORY_STRING
    return File { CharPointer_UTF8 { PIP_JUCE_EXAMPLES_DIRECTORY_STRING } };
   #else
    auto currentFile = File::getSpecialLocation (File::SpecialLocationType::currentApplicationFile);
    auto exampleDir = currentFile.getParentDirectory().getChildFile ("examples");

    if (exampleDir.exists())
        return exampleDir;

    // keep track of the number of parent directories so we don't go on endlessly
    for (int numTries = 0; numTries < 15; ++numTries)
    {
        if (currentFile.getFileName() == "examples")
            return currentFile;

        const auto sibling = currentFile.getSiblingFile ("examples");

        if (sibling.exists())
            return sibling;

        currentFile = currentFile.getParentDirectory();
    }

    return currentFile;
   #endif
}

inline std::unique_ptr<InputStream> createAssetInputStream (const char* resourcePath)
{
  #if JUCE_ANDROID
    ZipFile apkZip (File::getSpecialLocation (File::invokedExecutableFile));
    return std::unique_ptr<InputStream> (apkZip.createStreamForEntry (apkZip.getIndexOfFileName ("assets/" + String (resourcePath))));
  #else
   #if JUCE_IOS
    auto assetsDir = File::getSpecialLocation (File::currentExecutableFile)
                          .getParentDirectory().getChildFile ("Assets");
   #elif JUCE_MAC
    auto assetsDir = File::getSpecialLocation (File::currentExecutableFile)
                          .getParentDirectory().getParentDirectory().getChildFile ("Resources").getChildFile ("Assets");

    if (! assetsDir.exists())
        assetsDir = getExamplesDirectory().getChildFile ("Assets");
   #else
    auto assetsDir = getExamplesDirectory().getChildFile ("Assets");
   #endif

    auto resourceFile = assetsDir.getChildFile (resourcePath);
    jassert (resourceFile.existsAsFile());

    return resourceFile.createInputStream();
  #endif
}

inline Image getImageFromAssets (const char* assetName)
{
    auto hashCode = (String (assetName) + "@juce_demo_assets").hashCode64();
    auto img = ImageCache::getFromHashCode (hashCode);

    if (img.isNull())
    {
        std::unique_ptr<InputStream> juceIconStream (createAssetInputStream (assetName));

        if (juceIconStream == nullptr)
            return {};

        img = ImageFileFormat::loadFrom (*juceIconStream);

        ImageCache::addImageToCache (img, hashCode);
    }

    return img;
}

inline String loadEntireAssetIntoString (const char* assetName)
{
    std::unique_ptr<InputStream> input (createAssetInputStream (assetName));

    if (input == nullptr)
        return {};

    return input->readString();
}

//==============================================================================
inline Path getJUCELogoPath()
{
    return Drawable::parseSVGPath (
        "M72.87 84.28A42.36 42.36 0 0130.4 42.14a42.48 42.48 0 0184.95 0 42.36 42.36 0 01-42.48 42.14zm0-78.67A36.74 36.74 0 0036 42.14a36.88 36.88 0 0073.75 0A36.75 36.75 0 0072.87 5.61z"
        "M77.62 49.59a177.77 177.77 0 008.74 18.93A4.38 4.38 0 0092.69 70a34.5 34.5 0 008.84-9 4.3 4.3 0 00-2.38-6.49A176.73 176.73 0 0180 47.32a1.78 1.78 0 00-2.38 2.27zM81.05 44.27a169.68 169.68 0 0020.13 7.41 4.39 4.39 0 005.52-3.41 34.42 34.42 0 00.55-6.13 33.81 33.81 0 00-.67-6.72 4.37 4.37 0 00-6.31-3A192.32 192.32 0 0181.1 41a1.76 1.76 0 00-.05 3.27zM74.47 50.44a1.78 1.78 0 00-3.29 0 165.54 165.54 0 00-7.46 19.89 4.33 4.33 0 003.47 5.48 35.49 35.49 0 005.68.46 34.44 34.44 0 007.13-.79 4.32 4.32 0 003-6.25 187.83 187.83 0 01-8.53-18.79zM71.59 34.12a1.78 1.78 0 003.29.05 163.9 163.9 0 007.52-20.11A4.34 4.34 0 0079 8.59a35.15 35.15 0 00-13.06.17 4.32 4.32 0 00-3 6.26 188.41 188.41 0 018.65 19.1zM46.32 30.3a176.2 176.2 0 0120 7.48 1.78 1.78 0 002.37-2.28 180.72 180.72 0 00-9.13-19.84 4.38 4.38 0 00-6.33-1.47 34.27 34.27 0 00-9.32 9.65 4.31 4.31 0 002.41 6.46zM68.17 49.18a1.77 1.77 0 00-2.29-2.34 181.71 181.71 0 00-19.51 8.82A4.3 4.3 0 0044.91 62a34.36 34.36 0 009.42 8.88 4.36 4.36 0 006.5-2.38 175.11 175.11 0 017.34-19.32zM77.79 35.59a1.78 1.78 0 002.3 2.35 182.51 182.51 0 0019.6-8.88 4.3 4.3 0 001.5-6.25 34.4 34.4 0 00-9.41-9.14A4.36 4.36 0 0085.24 16a174.51 174.51 0 01-7.45 19.59zM64.69 40.6a167.72 167.72 0 00-20.22-7.44A4.36 4.36 0 0039 36.6a33.68 33.68 0 00-.45 5.54 34 34 0 00.81 7.4 4.36 4.36 0 006.28 2.84 189.19 189.19 0 0119-8.52 1.76 1.76 0 00.05-3.26zM20 129.315c0 5-2.72 8.16-7.11 8.16-2.37 0-4.17-1-6.2-3.56l-.69-.78-6 5 .57.76c3.25 4.36 7.16 6.39 12.31 6.39 9 0 15.34-6.57 15.34-16v-28.1H20zM61.69 126.505c0 6.66-3.76 11-9.57 11-5.81 0-9.56-4.31-9.56-11v-25.32h-8.23v25.69c0 10.66 7.4 18.4 17.6 18.4 10 0 17.61-7.72 18-18.4v-25.69h-8.24zM106.83 134.095c-3.58 2.43-6.18 3.38-9.25 3.38a14.53 14.53 0 010-29c3.24 0 5.66.88 9.25 3.38l.76.53 4.78-6-.75-.62a22.18 22.18 0 00-14.22-5.1 22.33 22.33 0 100 44.65 21.53 21.53 0 0014.39-5.08l.81-.64-5-6zM145.75 137.285h-19.06v-10.72h18.3v-7.61h-18.3v-10.16h19.06v-7.61h-27.28v43.53h27.28z"
        "M68.015 83.917c-7.723-.902-15.472-4.123-21.566-8.966-8.475-6.736-14.172-16.823-15.574-27.575C29.303 35.31 33.538 22.7 42.21 13.631 49.154 6.368 58.07 1.902 68.042.695c2.15-.26 7.524-.26 9.675 0 12.488 1.512 23.464 8.25 30.437 18.686 8.332 12.471 9.318 28.123 2.605 41.368-2.28 4.5-4.337 7.359-7.85 10.909A42.273 42.273 0 0177.613 83.92c-2.027.227-7.644.225-9.598-.003zm7.823-5.596c8.435-.415 17.446-4.678 23.683-11.205 5.976-6.254 9.35-13.723 10.181-22.537.632-6.705-1.346-14.948-5.065-21.108C98.88 13.935 89.397 7.602 78.34 5.906c-2.541-.39-8.398-.386-10.96.006C53.54 8.034 42.185 17.542 37.81 30.67c-2.807 8.426-2.421 17.267 1.11 25.444 4.877 11.297 14.959 19.41 26.977 21.709 2.136.408 6.1.755 7.377.645.325-.028 1.48-.094 2.564-.147z"
  );
}

//==============================================================================
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
 inline CodeEditorComponent::ColourScheme getDarkCodeEditorColourScheme()
 {
     struct Type
     {
         const char* name;
         juce::uint32 colour;
     };

     const Type types[] =
     {
         { "Error",              0xffe60000 },
         { "Comment",            0xff72d20c },
         { "Keyword",            0xffee6f6f },
         { "Operator",           0xffc4eb19 },
         { "Identifier",         0xffcfcfcf },
         { "Integer",            0xff42c8c4 },
         { "Float",              0xff885500 },
         { "String",             0xffbc45dd },
         { "Bracket",            0xff058202 },
         { "Punctuation",        0xffcfbeff },
         { "Preprocessor Text",  0xfff8f631 }
     };

     CodeEditorComponent::ColourScheme cs;

     for (auto& t : types)
         cs.set (t.name, Colour (t.colour));

     return cs;
 }

 inline CodeEditorComponent::ColourScheme getLightCodeEditorColourScheme()
 {
     struct Type
     {
         const char* name;
         juce::uint32 colour;
     };

     const Type types[] =
     {
         { "Error",              0xffcc0000 },
         { "Comment",            0xff00aa00 },
         { "Keyword",            0xff0000cc },
         { "Operator",           0xff225500 },
         { "Identifier",         0xff000000 },
         { "Integer",            0xff880000 },
         { "Float",              0xff885500 },
         { "String",             0xff990099 },
         { "Bracket",            0xff000055 },
         { "Punctuation",        0xff004400 },
         { "Preprocessor Text",  0xff660000 }
     };

     CodeEditorComponent::ColourScheme cs;

     for (auto& t : types)
         cs.set (t.name, Colour (t.colour));

     return cs;
 }
#endif

//==============================================================================
// This is basically a sawtooth wave generator - maps a value that bounces between
// 0.0 and 1.0 at a random speed
struct BouncingNumber
{
    BouncingNumber()
        : speed (0.0004 + 0.0007 * Random::getSystemRandom().nextDouble()),
          phase (Random::getSystemRandom().nextDouble())
    {
    }

    float getValue() const
    {
        double v = fmod (phase + speed * Time::getMillisecondCounterHiRes(), 2.0);
        return (float) (v >= 1.0 ? (2.0 - v) : v);
    }

protected:
    double speed, phase;
};

struct SlowerBouncingNumber  : public BouncingNumber
{
    SlowerBouncingNumber()
    {
        speed *= 0.3;
    }
};

#endif   // PIP_DEMO_UTILITIES_INCLUDED

JuceHeader.h

Just include everything for testing purposes

/*

    IMPORTANT! This file is auto-generated each time you save your
    project - if you alter its contents, your changes may be overwritten!

    This is the header file that your files should include in order to get all the
    JUCE library headers. You should avoid including the JUCE headers directly in
    your own source files, because that wouldn't pick up the correct configuration
    options for your app.

*/

#pragma once


#include <juce_analytics/juce_analytics.h>
#include <juce_audio_basics/juce_audio_basics.h>
#include <juce_audio_devices/juce_audio_devices.h>
#include <juce_audio_formats/juce_audio_formats.h>
#include <juce_audio_processors/juce_audio_processors.h>
#include <juce_audio_utils/juce_audio_utils.h>
#include <juce_box2d/juce_box2d.h>
#include <juce_core/juce_core.h>
#include <juce_cryptography/juce_cryptography.h>
#include <juce_data_structures/juce_data_structures.h>
#include <juce_dsp/juce_dsp.h>
#include <juce_events/juce_events.h>
#include <juce_graphics/juce_graphics.h>
#include <juce_gui_basics/juce_gui_basics.h>
#include <juce_gui_extra/juce_gui_extra.h>
#include <juce_opengl/juce_opengl.h>
#include <juce_osc/juce_osc.h>
#include <juce_product_unlocking/juce_product_unlocking.h>
#include <juce_video/juce_video.h>


#if defined (JUCE_PROJUCER_VERSION) && JUCE_PROJUCER_VERSION < JUCE_VERSION
 /** If you've hit this error then the version of the Projucer that was used to generate this project is
     older than the version of the JUCE modules being included. To fix this error, re-save your project
     using the latest version of the Projucer or, if you aren't using the Projucer to manage your project,
     remove the JUCE_PROJUCER_VERSION define.
 */
 #error "This project was last saved using an outdated version of the Projucer! Re-save this project with the latest version to fix this error."
#endif

#if ! DONT_SET_USING_JUCE_NAMESPACE
 // If your code uses a lot of JUCE classes, then this will obviously save you
 // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE.
 using namespace juce;
#endif

#if ! JUCE_DONT_DECLARE_PROJECTINFO
namespace ProjectInfo
{
    const char* const  projectName    = "DemoRunner";
    const char* const  companyName    = "Raw Material Software Limited";
    const char* const  versionString  = "6.1.5";
    const int          versionNumber  = 0x60105;
}
#endif