fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).

This commit is contained in:
Alex Birch
2018-06-17 13:34:53 +01:00
parent a2be47c887
commit dff4d13a1d
1563 changed files with 601601 additions and 3466 deletions

View File

@ -0,0 +1,108 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
ApplicationProperties::ApplicationProperties()
{
}
ApplicationProperties::~ApplicationProperties()
{
closeFiles();
}
//==============================================================================
void ApplicationProperties::setStorageParameters (const PropertiesFile::Options& newOptions)
{
options = newOptions;
}
//==============================================================================
void ApplicationProperties::openFiles()
{
// You need to call setStorageParameters() before trying to get hold of the properties!
jassert (options.applicationName.isNotEmpty());
if (options.applicationName.isNotEmpty())
{
PropertiesFile::Options o (options);
if (userProps == nullptr)
{
o.commonToAllUsers = false;
userProps.reset (new PropertiesFile (o));
}
if (commonProps == nullptr)
{
o.commonToAllUsers = true;
commonProps.reset (new PropertiesFile (o));
}
userProps->setFallbackPropertySet (commonProps.get());
}
}
PropertiesFile* ApplicationProperties::getUserSettings()
{
if (userProps == nullptr)
openFiles();
return userProps.get();
}
PropertiesFile* ApplicationProperties::getCommonSettings (const bool returnUserPropsIfReadOnly)
{
if (commonProps == nullptr)
openFiles();
if (returnUserPropsIfReadOnly)
{
if (commonSettingsAreReadOnly == 0)
commonSettingsAreReadOnly = commonProps->save() ? -1 : 1;
if (commonSettingsAreReadOnly > 0)
return userProps.get();
}
return commonProps.get();
}
bool ApplicationProperties::saveIfNeeded()
{
return (userProps == nullptr || userProps->saveIfNeeded())
&& (commonProps == nullptr || commonProps->saveIfNeeded());
}
void ApplicationProperties::closeFiles()
{
userProps.reset();
commonProps.reset();
}
} // namespace juce

View File

@ -0,0 +1,134 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Manages a collection of properties.
This is a slightly higher-level wrapper for managing PropertiesFile objects.
It holds two different PropertiesFile objects internally, one for user-specific
settings (stored in your user directory), and one for settings that are common to
all users (stored in a folder accessible to all users).
The class manages the creation of these files on-demand, allowing access via the
getUserSettings() and getCommonSettings() methods.
After creating an instance of an ApplicationProperties object, you should first
of all call setStorageParameters() to tell it the parameters to use to create
its files.
@see PropertiesFile
@tags{DataStructures}
*/
class JUCE_API ApplicationProperties
{
public:
//==============================================================================
/**
Creates an ApplicationProperties object.
Before using it, you must call setStorageParameters() to give it the info
it needs to create the property files.
*/
ApplicationProperties();
/** Destructor. */
~ApplicationProperties();
//==============================================================================
/** Gives the object the information it needs to create the appropriate properties files.
See the PropertiesFile::Options class for details about what options you need to set.
*/
void setStorageParameters (const PropertiesFile::Options& options);
/** Returns the current storage parameters.
@see setStorageParameters
*/
const PropertiesFile::Options& getStorageParameters() const noexcept { return options; }
//==============================================================================
/** Returns the user settings file.
The first time this is called, it will create and load the properties file.
Note that when you search the user PropertiesFile for a value that it doesn't contain,
the common settings are used as a second-chance place to look. This is done via the
PropertySet::setFallbackPropertySet() method - by default the common settings are set
to the fallback for the user settings.
@see getCommonSettings
*/
PropertiesFile* getUserSettings();
/** Returns the common settings file.
The first time this is called, it will create and load the properties file.
@param returnUserPropsIfReadOnly if this is true, and the common properties file is
read-only (e.g. because the user doesn't have permission to write
to shared files), then this will return the user settings instead,
(like getUserSettings() would do). This is handy if you'd like to
write a value to the common settings, but if that's no possible,
then you'd rather write to the user settings than none at all.
If returnUserPropsIfReadOnly is false, this method will always return
the common settings, even if any changes to them can't be saved.
@see getUserSettings
*/
PropertiesFile* getCommonSettings (bool returnUserPropsIfReadOnly);
//==============================================================================
/** Saves both files if they need to be saved.
@see PropertiesFile::saveIfNeeded
*/
bool saveIfNeeded();
/** Flushes and closes both files if they are open.
This flushes any pending changes to disk with PropertiesFile::saveIfNeeded()
and closes both files. They will then be re-opened the next time getUserSettings()
or getCommonSettings() is called.
*/
void closeFiles();
private:
//==============================================================================
PropertiesFile::Options options;
std::unique_ptr<PropertiesFile> userProps, commonProps;
int commonSettingsAreReadOnly = 0;
void openFiles();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ApplicationProperties)
};
} // namespace juce

View File

@ -0,0 +1,369 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace PropertyFileConstants
{
JUCE_CONSTEXPR static const int magicNumber = (int) ByteOrder::makeInt ('P', 'R', 'O', 'P');
JUCE_CONSTEXPR static const int magicNumberCompressed = (int) ByteOrder::makeInt ('C', 'P', 'R', 'P');
JUCE_CONSTEXPR static const char* const fileTag = "PROPERTIES";
JUCE_CONSTEXPR static const char* const valueTag = "VALUE";
JUCE_CONSTEXPR static const char* const nameAttribute = "name";
JUCE_CONSTEXPR static const char* const valueAttribute = "val";
}
//==============================================================================
PropertiesFile::Options::Options()
: commonToAllUsers (false),
ignoreCaseOfKeyNames (false),
doNotSave (false),
millisecondsBeforeSaving (3000),
storageFormat (PropertiesFile::storeAsXML),
processLock (nullptr)
{
}
File PropertiesFile::Options::getDefaultFile() const
{
// mustn't have illegal characters in this name..
jassert (applicationName == File::createLegalFileName (applicationName));
#if JUCE_MAC || JUCE_IOS
File dir (commonToAllUsers ? "/Library/"
: "~/Library/");
if (osxLibrarySubFolder != "Preferences" && ! osxLibrarySubFolder.startsWith ("Application Support"))
{
/* The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple
have changed their advice, and now stipulate that settings should go in "Library/Application Support".
Because older apps would be broken by a silent change in this class's behaviour, you must now
explicitly set the osxLibrarySubFolder value to indicate which path you want to use.
In newer apps, you should always set this to "Application Support"
or "Application Support/YourSubFolderName".
If your app needs to load settings files that were created by older versions of juce and
you want to maintain backwards-compatibility, then you can set this to "Preferences".
But.. for better Apple-compliance, the recommended approach would be to write some code that
finds your old settings files in ~/Library/Preferences, moves them to ~/Library/Application Support,
and then uses the new path.
*/
jassertfalse;
dir = dir.getChildFile ("Application Support");
}
else
{
dir = dir.getChildFile (osxLibrarySubFolder);
}
if (folderName.isNotEmpty())
dir = dir.getChildFile (folderName);
#elif JUCE_LINUX || JUCE_ANDROID
auto dir = File (commonToAllUsers ? "/var" : "~")
.getChildFile (folderName.isNotEmpty() ? folderName
: ("." + applicationName));
#elif JUCE_WINDOWS
auto dir = File::getSpecialLocation (commonToAllUsers ? File::commonApplicationDataDirectory
: File::userApplicationDataDirectory);
if (dir == File())
return {};
dir = dir.getChildFile (folderName.isNotEmpty() ? folderName
: applicationName);
#endif
return (filenameSuffix.startsWithChar (L'.')
? dir.getChildFile (applicationName).withFileExtension (filenameSuffix)
: dir.getChildFile (applicationName + "." + filenameSuffix));
}
//==============================================================================
PropertiesFile::PropertiesFile (const File& f, const Options& o)
: PropertySet (o.ignoreCaseOfKeyNames),
file (f), options (o)
{
reload();
}
PropertiesFile::PropertiesFile (const Options& o)
: PropertySet (o.ignoreCaseOfKeyNames),
file (o.getDefaultFile()), options (o)
{
reload();
}
bool PropertiesFile::reload()
{
ProcessScopedLock pl (createProcessLock());
if (pl != nullptr && ! pl->isLocked())
return false; // locking failure..
loadedOk = (! file.exists()) || loadAsBinary() || loadAsXml();
return loadedOk;
}
PropertiesFile::~PropertiesFile()
{
saveIfNeeded();
}
InterProcessLock::ScopedLockType* PropertiesFile::createProcessLock() const
{
return options.processLock != nullptr ? new InterProcessLock::ScopedLockType (*options.processLock) : nullptr;
}
bool PropertiesFile::saveIfNeeded()
{
const ScopedLock sl (getLock());
return (! needsWriting) || save();
}
bool PropertiesFile::needsToBeSaved() const
{
const ScopedLock sl (getLock());
return needsWriting;
}
void PropertiesFile::setNeedsToBeSaved (const bool needsToBeSaved_)
{
const ScopedLock sl (getLock());
needsWriting = needsToBeSaved_;
}
bool PropertiesFile::save()
{
const ScopedLock sl (getLock());
stopTimer();
if (options.doNotSave
|| file == File()
|| file.isDirectory()
|| ! file.getParentDirectory().createDirectory())
return false;
if (options.storageFormat == storeAsXML)
return saveAsXml();
return saveAsBinary();
}
bool PropertiesFile::loadAsXml()
{
XmlDocument parser (file);
std::unique_ptr<XmlElement> doc (parser.getDocumentElement (true));
if (doc != nullptr && doc->hasTagName (PropertyFileConstants::fileTag))
{
doc.reset (parser.getDocumentElement());
if (doc != nullptr)
{
forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag)
{
auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute);
if (name.isNotEmpty())
getAllProperties().set (name,
e->getFirstChildElement() != nullptr
? e->getFirstChildElement()->createDocument ("", true)
: e->getStringAttribute (PropertyFileConstants::valueAttribute));
}
return true;
}
// must be a pretty broken XML file we're trying to parse here,
// or a sign that this object needs an InterProcessLock,
// or just a failure reading the file. This last reason is why
// we don't jassertfalse here.
}
return false;
}
bool PropertiesFile::saveAsXml()
{
XmlElement doc (PropertyFileConstants::fileTag);
auto& props = getAllProperties();
for (int i = 0; i < props.size(); ++i)
{
auto* e = doc.createNewChildElement (PropertyFileConstants::valueTag);
e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]);
// if the value seems to contain xml, store it as such..
if (auto* childElement = XmlDocument::parse (props.getAllValues() [i]))
e->addChildElement (childElement);
else
e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]);
}
ProcessScopedLock pl (createProcessLock());
if (pl != nullptr && ! pl->isLocked())
return false; // locking failure..
if (doc.writeToFile (file, {}))
{
needsWriting = false;
return true;
}
return false;
}
bool PropertiesFile::loadAsBinary()
{
FileInputStream fileStream (file);
if (fileStream.openedOk())
{
auto magicNumber = fileStream.readInt();
if (magicNumber == PropertyFileConstants::magicNumberCompressed)
{
SubregionStream subStream (&fileStream, 4, -1, false);
GZIPDecompressorInputStream gzip (subStream);
return loadAsBinary (gzip);
}
if (magicNumber == PropertyFileConstants::magicNumber)
return loadAsBinary (fileStream);
}
return false;
}
bool PropertiesFile::loadAsBinary (InputStream& input)
{
BufferedInputStream in (input, 2048);
int numValues = in.readInt();
while (--numValues >= 0 && ! in.isExhausted())
{
auto key = in.readString();
auto value = in.readString();
jassert (key.isNotEmpty());
if (key.isNotEmpty())
getAllProperties().set (key, value);
}
return true;
}
bool PropertiesFile::saveAsBinary()
{
ProcessScopedLock pl (createProcessLock());
if (pl != nullptr && ! pl->isLocked())
return false; // locking failure..
TemporaryFile tempFile (file);
{
FileOutputStream out (tempFile.getFile());
if (! out.openedOk())
return false;
if (options.storageFormat == storeAsCompressedBinary)
{
out.writeInt (PropertyFileConstants::magicNumberCompressed);
out.flush();
GZIPCompressorOutputStream zipped (out, 9);
if (! writeToStream (zipped))
return false;
}
else
{
// have you set up the storage option flags correctly?
jassert (options.storageFormat == storeAsBinary);
out.writeInt (PropertyFileConstants::magicNumber);
if (! writeToStream (out))
return false;
}
}
if (! tempFile.overwriteTargetFileWithTemporary())
return false;
needsWriting = false;
return true;
}
bool PropertiesFile::writeToStream (OutputStream& out)
{
auto& props = getAllProperties();
auto& keys = props.getAllKeys();
auto& values = props.getAllValues();
auto numProperties = props.size();
if (! out.writeInt (numProperties))
return false;
for (int i = 0; i < numProperties; ++i)
{
if (! out.writeString (keys[i])) return false;
if (! out.writeString (values[i])) return false;
}
return true;
}
void PropertiesFile::timerCallback()
{
saveIfNeeded();
}
void PropertiesFile::propertyChanged()
{
sendChangeMessage();
needsWriting = true;
if (options.millisecondsBeforeSaving > 0)
startTimer (options.millisecondsBeforeSaving);
else if (options.millisecondsBeforeSaving == 0)
saveIfNeeded();
}
} // namespace juce

View File

@ -0,0 +1,256 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/** Wrapper on a file that stores a list of key/value data pairs.
Useful for storing application settings, etc. See the PropertySet class for
the interfaces that read and write values.
Not designed for very large amounts of data, as it keeps all the values in
memory and writes them out to disk lazily when they are changed.
Because this class derives from ChangeBroadcaster, ChangeListeners can be registered
with it, and these will be signalled when a value changes.
@see PropertySet
@tags{DataStructures}
*/
class JUCE_API PropertiesFile : public PropertySet,
public ChangeBroadcaster,
private Timer
{
public:
//==============================================================================
enum StorageFormat
{
storeAsBinary,
storeAsCompressedBinary,
storeAsXML
};
//==============================================================================
/** Structure describing properties file options */
struct JUCE_API Options
{
/** Creates an empty Options structure.
You'll need to fill-in the data members appropriately before using this structure.
*/
Options();
/** The name of your application - this is used to help generate the path and filename
at which the properties file will be stored. */
String applicationName;
/** The suffix to use for your properties file.
It doesn't really matter what this is - you may want to use ".settings" or
".properties" or something. If the suffix includes the prefixing dot (for example
".settings") then the suffix of applicationName will be replaced with your suffix
("MyApp.exe" -> "MyApp.settings"). If your filenameSuffix does NOT include the dot,
then the suffix will be appended to the applicationName ("MyApp.exe" ->
"MyApp.exe.settings").
*/
String filenameSuffix;
/** The name of a subfolder in which you'd like your properties file to live.
See the getDefaultFile() method for more details about how this is used.
*/
String folderName;
/** If you're using properties files on a Mac, you must set this value - failure to
do so will cause a runtime assertion.
The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple
have changed their advice, and now stipulate that settings should go in "Library/Application Support".
Because older apps would be broken by a silent change in this class's behaviour, you must now
explicitly set the osxLibrarySubFolder value to indicate which path you want to use.
In newer apps, you should always set this to "Application Support" or
"Application Support/YourSubFolderName".
If your app needs to load settings files that were created by older versions of juce and
you want to maintain backwards-compatibility, then you can set this to "Preferences".
But.. for better Apple-compliance, the recommended approach would be to write some code that
finds your old settings files in ~/Library/Preferences, moves them to ~/Library/Application Support,
and then uses the new path.
*/
String osxLibrarySubFolder;
/** If true, the file will be created in a location that's shared between users.
The default constructor initialises this value to false.
*/
bool commonToAllUsers;
/** If true, this means that property names are matched in a case-insensitive manner.
See the PropertySet constructor for more info.
The default constructor initialises this value to false.
*/
bool ignoreCaseOfKeyNames;
/** If set to true, this prevents the file from being written to disk. */
bool doNotSave;
/** If this is zero or greater, then after a value is changed, the object will wait
for this amount of time and then save the file. If this zero, the file will be
written to disk immediately on being changed (which might be slow, as it'll re-write
synchronously each time a value-change method is called). If it is less than zero,
the file won't be saved until save() or saveIfNeeded() are explicitly called.
The default constructor sets this to a reasonable value of a few seconds, so you
only need to change it if you need a special case.
*/
int millisecondsBeforeSaving;
/** Specifies whether the file should be written as XML, binary, etc.
The default constructor sets this to storeAsXML, so you only need to set it explicitly
if you want to use a different format.
*/
StorageFormat storageFormat;
/** An optional InterprocessLock object that will be used to prevent multiple threads or
processes from writing to the file at the same time. The PropertiesFile will keep a
pointer to this object but will not take ownership of it - the caller is responsible for
making sure that the lock doesn't get deleted before the PropertiesFile has been deleted.
The default constructor initialises this value to nullptr, so you don't need to touch it
unless you want to use a lock.
*/
InterProcessLock* processLock;
/** This can be called to suggest a file that should be used, based on the values
in this structure.
So on a Mac, this will return a file called:
~/Library/[osxLibrarySubFolder]/[folderName]/[applicationName].[filenameSuffix]
On Windows it'll return something like:
C:\\Documents and Settings\\username\\Application Data\\[folderName]\\[applicationName].[filenameSuffix]
On Linux it'll return
~/[folderName]/[applicationName].[filenameSuffix]
If the folderName variable is empty, it'll use the app name for this (or omit the
folder name on the Mac).
The paths will also vary depending on whether commonToAllUsers is true.
*/
File getDefaultFile() const;
};
//==============================================================================
/** Creates a PropertiesFile object.
The file used will be chosen by calling PropertiesFile::Options::getDefaultFile()
for the options provided. To set the file explicitly, use the other constructor.
*/
explicit PropertiesFile (const Options& options);
/** Creates a PropertiesFile object.
Unlike the other constructor, this one allows you to explicitly set the file that you
want to be used, rather than using the default one.
*/
PropertiesFile (const File& file,
const Options& options);
/** Destructor.
When deleted, the file will first call saveIfNeeded() to flush any changes to disk.
*/
~PropertiesFile();
//==============================================================================
/** Returns true if this file was created from a valid (or non-existent) file.
If the file failed to load correctly because it was corrupt or had insufficient
access, this will be false.
*/
bool isValidFile() const noexcept { return loadedOk; }
//==============================================================================
/** This will flush all the values to disk if they've changed since the last
time they were saved.
Returns false if it fails to write to the file for some reason (maybe because
it's read-only or the directory doesn't exist or something).
@see save
*/
bool saveIfNeeded();
/** This will force a write-to-disk of the current values, regardless of whether
anything has changed since the last save.
Returns false if it fails to write to the file for some reason (maybe because
it's read-only or the directory doesn't exist or something).
@see saveIfNeeded
*/
bool save();
/** Returns true if the properties have been altered since the last time they were saved.
The file is flagged as needing to be saved when you change a value, but you can
explicitly set this flag with setNeedsToBeSaved().
*/
bool needsToBeSaved() const;
/** Explicitly sets the flag to indicate whether the file needs saving or not.
@see needsToBeSaved
*/
void setNeedsToBeSaved (bool needsToBeSaved);
/** Attempts to reload the settings from the file. */
bool reload();
//==============================================================================
/** Returns the file that's being used. */
const File& getFile() const noexcept { return file; }
protected:
/** @internal */
void propertyChanged() override;
private:
//==============================================================================
File file;
Options options;
bool loadedOk = false, needsWriting = false;
using ProcessScopedLock = const std::unique_ptr<InterProcessLock::ScopedLockType>;
InterProcessLock::ScopedLockType* createProcessLock() const;
void timerCallback() override;
bool saveAsXml();
bool saveAsBinary();
bool loadAsXml();
bool loadAsBinary();
bool loadAsBinary (InputStream&);
bool writeToStream (OutputStream&);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertiesFile)
};
} // namespace juce