Rewrite save/load state via JSON.
Remember to update GUI after state changed.
This commit is contained in:
parent
c75d2a60dd
commit
25dd5a5707
2 changed files with 44 additions and 37 deletions
|
@ -4,6 +4,8 @@
|
|||
#include "IntFloatParameter.h"
|
||||
#include "SbiLoader.h"
|
||||
|
||||
const char *JuceOplvstiAudioProcessor::PROGRAM_INDEX = "Program Index";
|
||||
|
||||
//==============================================================================
|
||||
JuceOplvstiAudioProcessor::JuceOplvstiAudioProcessor()
|
||||
: i_program(-1)
|
||||
|
@ -739,62 +741,67 @@ AudioProcessorEditor* JuceOplvstiAudioProcessor::createEditor()
|
|||
return gui;
|
||||
}
|
||||
|
||||
// FIXME: these two funcs and get-/setStateInformation should be replaced by a proper cross-platform archiving API, e.g. eos portable archive or boost text archive
|
||||
template<class T>
|
||||
void push(char *&cursor, T value)
|
||||
{
|
||||
*reinterpret_cast<T *>(cursor)=value;
|
||||
cursor+=sizeof(T);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void pop(const char *&cursor, T &value)
|
||||
{
|
||||
value=*reinterpret_cast<const T *>(cursor);
|
||||
cursor+=sizeof(T);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void JuceOplvstiAudioProcessor::getStateInformation (MemoryBlock& destData)
|
||||
|
||||
// JUCE requires that JSON names are valid Identifiers (restricted character set) even though the JSON standard allows any valid string.
|
||||
// Per http://www.juce.com/forum/topic/problem-spaces-json-identifier jules allowed Strings to bypass the assertion check
|
||||
// but a regression occured in 4317f60 re-enabling this check, so we need to sanitize the names.
|
||||
// Technically, the code still works without this, but it will trigger a gargantuan number of assertions hindering effective debugging.
|
||||
Identifier stringToIdentifier(const String &s)
|
||||
{
|
||||
destData.ensureSize(sizeof(CURRENT_VERSION)+sizeof(i_program)+sizeof(float) * getNumParameters());
|
||||
return s.replaceCharacters(" ", "_");
|
||||
}
|
||||
|
||||
char *cursor = static_cast<char *>(destData.getData());
|
||||
void JuceOplvstiAudioProcessor::getStateInformation(MemoryBlock& destData)
|
||||
{
|
||||
ReferenceCountedObjectPtr<DynamicObject> v(new DynamicObject);
|
||||
|
||||
push(cursor, CURRENT_VERSION);
|
||||
push(cursor, i_program);
|
||||
v->setProperty(stringToIdentifier(PROGRAM_INDEX), i_program);
|
||||
|
||||
for (int i = 0; i < getNumParameters(); i++) {
|
||||
float p = getParameter(i);
|
||||
push(cursor, p);
|
||||
double p = getParameter(i);
|
||||
|
||||
v->setProperty(stringToIdentifier(getParameterName(i)), p);
|
||||
}
|
||||
|
||||
String s = JSON::toString(v.get());
|
||||
|
||||
destData.setSize(s.length());
|
||||
destData.copyFrom(s.getCharPointer(), 0, destData.getSize());
|
||||
}
|
||||
|
||||
void JuceOplvstiAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
|
||||
{
|
||||
if (sizeInBytes < sizeof(CURRENT_VERSION))
|
||||
if (sizeInBytes < 1)
|
||||
return;
|
||||
|
||||
const char *cursor = static_cast<const char *>(data);
|
||||
const char *end = cursor+sizeInBytes;
|
||||
int version;
|
||||
const char *first = static_cast<const char *>(data);
|
||||
const char *last = first + sizeInBytes - 1;
|
||||
|
||||
pop(cursor, version);
|
||||
|
||||
if (version == CURRENT_VERSION)
|
||||
// simple check for JSON data - assume always object
|
||||
if (*first=='{' && *last=='}')
|
||||
{
|
||||
pop(cursor, i_program);
|
||||
// json format
|
||||
String s(first, sizeInBytes);
|
||||
var v = JSON::fromString(s);
|
||||
|
||||
const int parametersToLoad = std::min<int>(static_cast<int>(std::distance(cursor, end)) / sizeof(float), getNumParameters());
|
||||
|
||||
for (int i = 0; i < parametersToLoad; i++)
|
||||
{
|
||||
float p;
|
||||
var program = v[stringToIdentifier(PROGRAM_INDEX)];
|
||||
|
||||
pop(cursor, p);
|
||||
setParameter(i, p);
|
||||
if (!program.isVoid())
|
||||
i_program = program;
|
||||
}
|
||||
|
||||
for (int i=0; i<getNumParameters(); ++i)
|
||||
{
|
||||
var param = v[stringToIdentifier(getParameterName(i))];
|
||||
|
||||
if (!param.isVoid())
|
||||
setParameter(i, param);
|
||||
}
|
||||
|
||||
updateGuiIfPresent();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ private:
|
|||
int i_program;
|
||||
bool velocity;
|
||||
static const int NO_NOTE=-1;
|
||||
static const int CURRENT_VERSION = 0x09720100; // OPL2 v01.00 magic
|
||||
static const char *PROGRAM_INDEX;
|
||||
int active_notes[Hiopl::CHANNELS+1]; // keyed by channel
|
||||
std::deque<int> available_channels; // most recently freed at end
|
||||
std::deque<int> used_channels; // most recently used at end
|
||||
|
|
Loading…
Reference in a new issue