String LoadSave::getLicense(var state) { if (!state.isObject()) return ""; DynamicObject* object_state = state.getDynamicObject(); NamedValueSet properties = object_state->getProperties(); if (properties.contains("license")) return properties["license"]; return ""; }
void LoadSave::varToState(SynthBase* synth, std::map<std::string, String>& save_info, var state) { if (!state.isObject()) return; DynamicObject* object_state = state.getDynamicObject(); NamedValueSet properties = object_state->getProperties(); // Version 0.4.1 was the last build before we saved the version number. String version = "0.4.1"; if (properties.contains("synth_version")) version = properties["synth_version"]; // After 0.4.1 there was a patch file restructure. if (compareVersionStrings(version, "0.4.1") <= 0) { NamedValueSet new_properties; new_properties.set("settings", object_state); properties = new_properties; } var settings = properties["settings"]; DynamicObject* settings_object = settings.getDynamicObject(); NamedValueSet settings_properties = settings_object->getProperties(); Array<var>* modulations = settings_properties["modulations"].getArray(); // After 0.5.0 mixer was added and osc_mix was removed. And scaling of oscillators was changed. if (compareVersionStrings(version, "0.5.0") <= 0) { // Fix control control values. if (settings_properties.contains("osc_mix")) { mopo::mopo_float osc_mix = settings_properties["osc_mix"]; settings_properties.set("osc_1_volume", sqrt(1.0f - osc_mix)); settings_properties.set("osc_2_volume", sqrt(osc_mix)); settings_properties.remove("osc_mix"); } // Fix modulation routing. var* modulation = modulations->begin(); Array<var> old_modulations; Array<DynamicObject*> new_modulations; for (; modulation != modulations->end(); ++modulation) { DynamicObject* mod = modulation->getDynamicObject(); String destination = mod->getProperty("destination").toString(); if (destination == "osc_mix") { String source = mod->getProperty("source").toString(); mopo::mopo_float amount = mod->getProperty("amount"); old_modulations.add(mod); DynamicObject* osc_1_mod = new DynamicObject(); osc_1_mod->setProperty("source", source); osc_1_mod->setProperty("destination", "osc_1_volume"); osc_1_mod->setProperty("amount", -amount); new_modulations.add(osc_1_mod); DynamicObject* osc_2_mod = new DynamicObject(); osc_2_mod->setProperty("source", source); osc_2_mod->setProperty("destination", "osc_2_volume"); osc_2_mod->setProperty("amount", amount); new_modulations.add(osc_2_mod); } } for (var old_modulation : old_modulations) modulations->removeFirstMatchingValue(old_modulation); for (DynamicObject* modulation : new_modulations) modulations->add(modulation); } if (compareVersionStrings(version, "0.7.2") <= 0) { bool stutter_on = settings_properties["stutter_on"]; if (stutter_on) { settings_properties.set("stutter_resample_sync", 0); settings_properties.set("stutter_sync", 0); } } loadControls(synth, settings_properties); loadModulations(synth, modulations); loadSaveState(save_info, properties); }
bool compare::equality(var& x, var& y) { // 1. If Type(x) is the same as Type(y), then if (x.adapter->type == y.adapter->type) { // 1. If Type(x) is Undefined, return true. if (x.isUndefined()) return true; // 2. If Type(x) is Null, return true. if (x.isNull()) return true; // 3. If Type(x) is Number, then if (x.isNumber()) { // 1. If x is NaN, return false. // 2. If y is NaN, return false. // (TODO: NaN checks?) // 3. If x is the same Number value as y, return true. if (x.numberValue == y.numberValue) return true; // 4. If x is +0 and y is -0, return true. if (x.numberValue == +0 && y.numberValue == -0) return true; // 5. If x is -0 and y is +0, return true. if (x.numberValue == -0 && y.numberValue == +0) return true; // 6. Return false. return false; } // 4. If Type(x) is String, then return true if x and y are exactly the same sequence of characters // (same length and same characters in corresponding positions). Otherwise, return false. if (x.isString()) return x.stringValue == y.stringValue; // 5. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false. if (x.isBoolean()) return x.booleanValue == y.booleanValue; // 6. Return true if x and y refer to the same object. Otherwise, return false. if (x.isObject()) return x.objectValue == y.objectValue; if (x.isArray()) return x.arrayValue == y.arrayValue; return false; } // 2. If x is null and y is undefined, return true. if (x.isNull() && y.isUndefined()) return true; // 3. If x is undefined and y is null, return true. if (x.isUndefined() && y.isNull()) return true; // 4. If Type(x) is Number and Type(y) is String, // return the result of the comparison x == ToNumber(y). if (x.isNumber() && y.isString()) return x == (number) y; // 5. If Type(x) is String and Type(y) is Number, // return the result of the comparison ToNumber(x) == y. if (x.isString() && y.isNumber()) return (var) (number) x == y; // 6. If Type(x) is Boolean, // return the result of the comparison ToNumber(x) == y. if (x.isBoolean()) return (var) (number) x == y; // 7. If Type(y) is Boolean, // return the result of the comparison x == ToNumber(y). if (y.isBoolean()) return x == (number) y; // 8. If Type(x) is either String or Number and Type(y) is Object, // return the result of the comparison x == ToPrimitive(y). if ((x.isString() || x.isNumber()) && (y.isObject() || y.isArray())) return x == (string) y; // 9. If Type(x) is Object and Type(y) is either String or Number, // return the result of the comparison ToPrimitive(x) == y. if ((x.isObject() || x.isArray()) && (y.isString() || y.isNumber())) return (var) (string) x == y; // 10. Return false. return false; }
var compare::toPrimitive(var& x) { if (!(x.isArray() || x.isObject())) return x; return (string) x; }
void LoadSave::varToState(mopo::HelmEngine* synth, const CriticalSection& critical_section, var state) { if (!state.isObject()) return; mopo::control_map controls = synth->getControls(); DynamicObject* object_state = state.getDynamicObject(); ScopedLock lock(critical_section); NamedValueSet properties = object_state->getProperties(); int size = properties.size(); for (int i = 0; i < size; ++i) { Identifier id = properties.getName(i); if (id.isValid()) { std::string name = id.toString().toStdString(); if (controls.count(name)) { mopo::mopo_float value = properties.getValueAt(i); controls[name]->set(value); } } } synth->clearModulations(); Array<var>* modulations = object_state->getProperty("modulations").getArray(); var* modulation = modulations->begin(); for (; modulation != modulations->end(); ++modulation) { DynamicObject* mod = modulation->getDynamicObject(); std::string source = mod->getProperty("source").toString().toStdString(); std::string destination = mod->getProperty("destination").toString().toStdString(); mopo::ModulationConnection* connection = new mopo::ModulationConnection(source, destination); connection->amount.set(mod->getProperty("amount")); synth->connectModulation(connection); } }