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