Skip to content

Instantly share code, notes, and snippets.

@tomfclarke
Created March 6, 2020 12:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomfclarke/41084c04618fee27df3a19b35626880a to your computer and use it in GitHub Desktop.
Save tomfclarke/41084c04618fee27df3a19b35626880a to your computer and use it in GitHub Desktop.
Command-line utility to convert AU presets saved with a JUCE plug-in to XML state.
/*******************************************************************************
The block below describes the properties of this PIP. A PIP is a short snippet
of code that can be read by the Projucer and used to generate a JUCE project.
BEGIN_JUCE_PIP_METADATA
name: JucePluginAUPresetToXML
description: Command-line utility to convert AU presets saved with a JUCE plug-in to XML state that can be loaded by AudioProcessorValueTreeState.
dependencies: juce_audio_basics, juce_audio_processors, juce_core, juce_data_structures, juce_events,
juce_graphics, juce_gui_basics, juce_gui_extra
exporters: xcode_mac
moduleFlags: JUCE_STRICT_REFCOUNTEDPOINTER=1
type: Console
mainClass: AUPresetToXML
END_JUCE_PIP_METADATA
*******************************************************************************/
#pragma once
#include <JuceHeader.h>
String readAUPreset (StringRef text)
{
CFDataRef xmlData = CFDataCreate (kCFAllocatorDefault,
reinterpret_cast<UInt8*>(text.text.getAddress()),
static_cast<CFIndex>(text.length()));
CFDictionaryRef dict = (CFDictionaryRef) CFPropertyListCreateWithData(kCFAllocatorDefault,
xmlData,
kCFPropertyListImmutable,
NULL,
NULL);
CFDataRef data = nullptr;
CFStringRef key = CFStringCreateWithCString (kCFAllocatorDefault, "jucePluginState", kCFStringEncodingUTF8);
bool valuePresent = CFDictionaryGetValueIfPresent (dict, key, (const void**) &data);
CFRelease (key);
if (valuePresent)
{
if (data != nullptr)
{
const int numBytes = (int) CFDataGetLength (data);
const juce::uint8* const bytes = CFDataGetBytePtr (data);
if (numBytes > 0)
{
MemoryBlock data (bytes, numBytes);
if (auto preset = AudioProcessor::getXmlFromBinary (data.getData(), int (data.getSize())))
{
return preset->toString();
}
}
}
}
return {};
}
void convertAUPresetFileToXML (File auPresetFile)
{
if (!auPresetFile.exists())
ConsoleApplication::fail (auPresetFile.getFullPathName() + " doesn't exist");
if (auPresetFile.isDirectory())
ConsoleApplication::fail (auPresetFile.getFullPathName() + " is a directory");
if (auPresetFile.getFileExtension() != ".aupreset")
ConsoleApplication::fail (auPresetFile.getFullPathName() + " is not an aupreset file");
StringArray lines;
auPresetFile.readLines (lines);
if (lines.size() == 0)
ConsoleApplication::fail ("Failed to read input file: "
+ auPresetFile.getFullPathName());
auto xml = readAUPreset (lines.joinIntoString (""));
File xmlFile = auPresetFile.withFileExtension ("xml");
Result createAction = xmlFile.create();
if (createAction.failed())
ConsoleApplication::fail ("Failed to create output file (" +
createAction.getErrorMessage() +
"): " +
xmlFile.getFullPathName());
if (!xmlFile.replaceWithText (xml))
ConsoleApplication::fail ("Failed to write to output file: " +
xmlFile.getFullPathName());
}
//==============================================================================
int main (int argc, char* argv[])
{
ConsoleApplication app;
app.addHelpCommand ("--help|-h", "Usage:", true);
app.addVersionCommand ("--version|-v", "JucePluginAUPresetToXML version 1.0.0");
app.addCommand ({ "--convert",
"--convert=filename",
"Converts an .aupreset file to XML.",
"Parses an .aupreset file and attempts to extract juce "
"ValueTree XML data. If found, outputs the data to a new "
"XML file in the same location as the original.",
[](const ArgumentList& args)
{
auto file = args.getFileForOption ("--convert");
convertAUPresetFileToXML (file);
}
});
return app.findAndRunCommand (argc, argv);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment