コード例 #1
0
ファイル: MLParameter.cpp プロジェクト: barnone/madronalib
MLPublishedParam::MLPublishedParam(const MLPath & procPath, const MLSymbol name, const MLSymbol alias, const MLSymbol type, int idx) :
	mPublishedAlias(alias),
	mIndex(idx),
	mAutomatable(true),
	mFlip(false)
{
	setRange(0.f, 1.f, 0.01f, false, 0.f);
	mUnit = kJucePluginParam_Generic;
	mWarpMode = kJucePluginParam_Linear;
	mParamValue = 0.f;
	mDefault = 0.f;
	mZeroThreshold = 0.f - (MLParamValue)(2 << 16);
	mGroupIndex = -1;
	addAddress(procPath, name);
	
	// default type is float
	if(type == MLSymbol())
	{
		mType = MLSymbol("float");
	}
	else
	{
		mType = type;
	}
}
コード例 #2
0
ファイル: MLSymbol.cpp プロジェクト: EQ4/madronalib
// add a number n to the end of a symbol after removing any final number.
// n must be >= 0.
MLSymbol MLSymbol::withFinalNumber(int n) const
{
	// *not* static because different threads could collide accesing a single buffer.
	char tempBuf[kMLMaxSymbolLength + kMLMaxNumberLength] = {0};
	
	const std::string& str = getString();
	const char* p = str.c_str();
	
	int i, j;
	int l = 0;
	
	// set l to length
	while(p[l])
	{
		l++;
	}
	// find last non-number character
	for (i = l-1; i >= 0; --i)
	{
		if (!isDigit(p[i])) break;
	}	
	// copy symbol without number to temp 
	for(j=0; j<=i; ++j)
	{
		tempBuf[j] = p[j];
	}
	
	naturalNumberToDigits(n, tempBuf+j);
	
	//debug() << "in: " << n << ", char*: " << tempBuf << ", Symbol " << MLSymbol(tempBuf) << "\n";	
	return MLSymbol(tempBuf);
}
コード例 #3
0
ファイル: MLSymbol.cpp プロジェクト: EQ4/madronalib
// remove any final number.
MLSymbol MLSymbol::withoutFinalNumber() const
{
	// *not* static because different threads could collide accessing a single buffer.
	char tempBuf[kMLMaxSymbolLength] = {0};
	
	const std::string& str = getString();
	const char* p = str.c_str();
	int i, j;
	int l = 0;
	
	// set l to length
	while(p[l])
	{
		l++;
	}
	// find last non-number character
	for (i = l-1; i >= 0; --i)
	{
		if (!isDigit(p[i])) break;
	}	
	// copy symbol without number to temp 
	for(j=0; j<=i; ++j)
	{
		tempBuf[j] = p[j];
	}
	tempBuf[i+1] = 0;
	return MLSymbol(tempBuf);
}
コード例 #4
0
ファイル: MLSymbol.cpp プロジェクト: drobilla/madronalib
// base-26 arithmetic with letters produces A, B, ... Z, AA, AB ...
const MLSymbol MLNameMaker::nextName()
{
	std::string nameStr;
	const int base = 26;
	const char baseChar = 'A';
	int a, m, d, rem;
	
	std::list<int> digits;
	a = index++;
	
	if (!a)
	{
		digits.push_front(0);
	}
	else while(a)
	{
		d = a / base;
		m = d * base;
		rem = a - m;
		digits.push_front(rem);
		a = d;
	}
		
	while(digits.size())
	{
		d = digits.front();
		digits.pop_front();
		nameStr += (char)d + baseChar;
	}
		
	return MLSymbol(nameStr.c_str());
}
コード例 #5
0
ファイル: MLSymbol.cpp プロジェクト: EQ4/madronalib
// replace wild card with the given number.
MLSymbol MLSymbol::withWildCardNumber(int n) const
{
	const std::string& inStr = getString();
	const char* p = inStr.c_str();
	int l = 0;
	int m = 0;
	char c;
	char tempBuf[kMLMaxSymbolLength] = {0};
	
	while(p[l] && (m < kMLMaxSymbolLength-1))
	{
		c = p[l];
		if (c == '*')
		{
			const char* d = positiveIntToDigits(n);
			int j = 0;
			while(d[j] && (m < kMLMaxSymbolLength-1))
			{
				tempBuf[m] = d[j];
				j++;
				m++;
			}
			m--;
		}
		else
		{
			tempBuf[m] = c;
		}
		l++;
		m++;
	}
	tempBuf[m] = 0;
	return MLSymbol(tempBuf);
}
コード例 #6
0
ファイル: MLPath.cpp プロジェクト: afofo/madronalib
// parse an input string into our representation: an array of MLSymbols.
MLPath::MLPath(const char * str) :
	mStart(0), mEnd(0), mCopy(0)
{
	memset(mpData, '\0', kMLPathMaxSymbols*sizeof(MLSymbol));
	unsigned symStart = 0;
	unsigned symEnd = 0;
	
	// get token up to each delimiter
	int endPos = 0;
	while(str[endPos])
	{
		for(endPos = symStart; str[endPos]; endPos++)
		{
			if (str[endPos] == '/') 
			{
				break;
			}
		}
		symEnd = endPos - 1;
		
		// make symbol
		addSymbol(MLSymbol(str+symStart, symEnd - symStart + 1));
		symStart = symEnd + 2;
	}
}
コード例 #7
0
ファイル: MLSignalView.cpp プロジェクト: EQ4/madronalib
void MLSignalView::setupSignalView (MLDSPEngine* pEng, const MLSymbol sigName, int voices)
{
	mViewingSignal = true;
	mpEngine = pEng;
	mSignalName = sigName;
	if(voices != mVoices)
	{
		mpWidget->setProperty(MLSymbol("voices"), voices);
		mVoices = voices;
	}
}
コード例 #8
0
ファイル: MLProc.cpp プロジェクト: afofo/madronalib
MLSymbol MLProc::getOutputName(int index)
{	
	if (procInfo().hasVariableOutputs())
	{
		return MLSymbol("out").withFinalNumber(index);
	}
	else if (index <= (int)mOutputs.size())
	{		
		MLSymbolMap& map = procInfo().getOutputMap();
		for (MLSymbolMap::MLSymbolMapIter i = map.begin(); i != map.end(); i++)
		{
			if ((*i).second == index)
			{
				return ((*i).first);
			}
		}
	} 

	return MLSymbol();
}
コード例 #9
0
void MLPluginController::processFileFromCollection (MLSymbol action, const MLFile fileToProcess, const MLFileCollection& collection, int idx, int size)
{
	MLSymbol collectionName(collection.getName());
	if(action == "process")
	{
		if(collectionName.beginsWith(MLSymbol("convert_presets")))
		{			
			// add file action to queue
			FileAction f(action, fileToProcess, &collection, idx, size);
			PaUtil_WriteRingBuffer( &mFileActionQueue, &f, 1 );
		}
	}
}
コード例 #10
0
void SoundplaneModel::setAllPropertiesToDefaults()
{
	// parameter defaults and creation
	setProperty("max_touches", 4);
	setProperty("lopass", 100.);
	
	setProperty("z_thresh", 0.01);
	setProperty("z_max", 0.05);
	setProperty("z_curve", 0.25);
	setProperty("display_scale", 1.);
	
	setProperty("quantize", 1.);
	setProperty("lock", 0.);
	setProperty("abs_rel", 0.);
	setProperty("snap", 250.);
	setProperty("vibrato", 0.5);
		
	setProperty("t_thresh", 0.2);
	
	setProperty("midi_active", 0);
	setProperty("midi_multi_chan", 1);
	setProperty("midi_start_chan", 1);
	setProperty("data_freq_midi", 250.);
	
	setProperty("kyma_poll", 1);
	
	setProperty("osc_active", 1);
	setProperty("osc_raw", 0);
	setProperty("data_freq_osc", 250.);
	
	setProperty("bend_range", 48);
	setProperty("transpose", 0);
	setProperty("bg_filter", 0.05);
	
	setProperty("hysteresis", 0.5);
	
	// menu param defaults
	setProperty("viewmode", "calibrated");
    
    // preset menu defaults (TODO use first choices?)
	setProperty("zone_preset", "continuous pitch x");
	setProperty("touch_preset", "touch default");
    
	setProperty("view_page", 0);
    
	for(int i=0; i<32; ++i)
	{
		setProperty(MLSymbol("carrier_toggle").withFinalNumber(i), 1);		
	}
}
コード例 #11
0
// setup info pertaining to the plugin format we are controlling
//
void MLPluginController::initialize()
{
    AudioProcessor::WrapperType w = getProcessor()->wrapperType;
    
	std::string regStr, bitsStr, pluginType;
	switch(w)
	{
		case AudioProcessor::wrapperType_VST:
			pluginType = "VST";
		break;
		case AudioProcessor::wrapperType_AudioUnit:
			pluginType = "AU";
		break;
		case AudioProcessor::wrapperType_Standalone:
			pluginType = "App";
		break;
		default:
			pluginType = "?";
		break;
	}
		
	#if (__LP64__) || (_WIN64)
		bitsStr = ".64";
	#else
		bitsStr = ".32";
	#endif

	mVersionString = std::string("version ");
	mVersionString += (std::string(MLProjectInfo::versionString));
	mVersionString += " (" + pluginType + bitsStr + ")";
	
	regStr = mVersionString;
	#if DEMO
		regStr += " DEMO\n";
	#else
		regStr += ", licensed to:\n";
	#endif
	
	MLAppView* myView = getView();
    if(myView)
    {
        MLLabel* regLabel = static_cast<MLLabel*>(myView->getWidget("reg"));
        if(regLabel)
        {
            regLabel->setPropertyImmediate(MLSymbol("text"), regStr);
        }
    }
	startTimer(kControllerTimerRate);
}
コード例 #12
0
void MLPluginProcessor::loadPluginDescription(const char* desc)
{
	mpPluginDoc = new XmlDocument(String(desc));
	
	if (mpPluginDoc.get())
	{
		ScopedPointer<XmlElement> doc (mpPluginDoc->getDocumentElement(true));
		if (doc)	// true = quick scan header
		{
			mEngine.scanDoc(&*mpPluginDoc, &mNumParameters);
			debug() << "loaded " << JucePlugin_Name << " plugin description, " << mNumParameters << " parameters.\n";
		}
		else
		{
			MLError() << "MLPluginProcessor: error loading plugin description!\n";
		}   
	}
	else
	{
		MLError() << "MLPluginProcessor: couldn't load plugin description!\n";
		return;
	}
	
	// get plugin parameters and initial values and create corresponding model properties.
	int params = getNumParameters();
	for(int i=0; i<params; ++i)
	{
		MLPublishedParamPtr p = getParameterPtr(i);
		MLPublishedParam* param = &(*p);
		if(param)
		{
			MLSymbol type = param->getType();
			if((type == "float") || (type == MLSymbol()))
			{
				debug() << param->getAlias() << " is a float type \n";
				setProperty(param->getAlias(), param->getDefault());
			}
			else
			{
				debug() << param->getAlias() << " is a non-float type \n";
			}
		}
	}
}
コード例 #13
0
const String MLPluginProcessor::getParameterName (int index)
{
	MLSymbol nameSym;
	const int p = mEngine.getPublishedParams(); 
	if (index < mNumParameters)
	{
		if (p == 0) // doc has been scanned but not built
		{
			nameSym = MLSymbol("param").withFinalNumber(index);
		}
		else
		{
			// graph has been built
			nameSym = mEngine.getParamPtr(index)->getAlias();	
	//debug() << "getParameterName: " << index << " is " << nameSym.getString().c_str() << ".\n";
		}
	}
 	return (String(nameSym.getString().c_str()));
}
コード例 #14
0
const MLSymbol MLPluginProcessor::XMLAttrToSymbol(const String& str)
{
	std::string strCopy(str.toUTF8());
	
	unsigned len = strCopy.length();
	for(unsigned c = 0; c < len; ++c)
	{
		unsigned char k = strCopy[c];
		if(k == ':')
		{
			strCopy[c] = '#';
		}
		else if(k == 0xB7)
		{
			strCopy[c] = '*';
		}
	}
 	return (MLSymbol(strCopy.c_str()));
}
コード例 #15
0
ファイル: MLSymbol.cpp プロジェクト: EQ4/madronalib
const MLSymbol MLNameMaker::nextName()
{
	return MLSymbol(nextNameAsString().c_str());
}
コード例 #16
0
ファイル: MLPluginView.cpp プロジェクト: EQ4/madronalib
MLEnvelope* MLPluginView::addEnvelope(const MLRect & r, const MLSymbol paramName)
{
	MLEnvelope * pE = new MLEnvelope();
    
	const std::string paramStr = paramName.getString();
	addPropertyView(MLSymbol(paramStr + "_delay"), pE, MLSymbol("delay"));
	addPropertyView(MLSymbol(paramStr + "_attack"), pE, MLSymbol("attack"));
	addPropertyView(MLSymbol(paramStr + "_decay"), pE, MLSymbol("decay"));
	addPropertyView(MLSymbol(paramStr + "_sustain"), pE, MLSymbol("sustain"));
	addPropertyView(MLSymbol(paramStr + "_release"), pE, MLSymbol("release"));
	addPropertyView(MLSymbol(paramStr + "_repeat"), pE, MLSymbol("repeat"));
	
	addWidgetToView(pE, r, paramName);
	return(pE);
}
コード例 #17
0
void SoundplaneModel::doPropertyChangeAction(MLSymbol p, const MLProperty & newVal)
{
	// debug() << "SoundplaneModel::doPropertyChangeAction: " << p << " -> " << newVal << "\n";
	
	int propertyType = newVal.getType();
	switch(propertyType)
	{
		case MLProperty::kFloatProperty:
		{
			float v = newVal.getFloatValue();
			if (p.withoutFinalNumber() == MLSymbol("carrier_toggle"))
			{
				// toggles changed -- mute carriers
				unsigned long mask = 0;
				for(int i=0; i<32; ++i)
				{
					MLSymbol tSym = MLSymbol("carrier_toggle").withFinalNumber(i);
					bool on = (int)(getFloatProperty(tSym));
					mask = mask | (on << i);
				}
				
				mCarriersMask = mask;
				mCarrierMaskDirty = true; // trigger carriers set in a second or so
			}
			
			else if (p == "all_toggle")
			{
				bool on = (bool)(v);
				for(int i=0; i<32; ++i)
				{
					MLSymbol tSym = MLSymbol("carrier_toggle").withFinalNumber(i);
					setProperty(tSym, on);
				}
				mCarriersMask = on ? ~0 : 0;
				mCarrierMaskDirty = true; // trigger carriers set in a second or so
			}
			else if (p == "max_touches")
			{
				mTracker.setMaxTouches(v);
				mMIDIOutput.setMaxTouches(v);
				mOSCOutput.setMaxTouches(v);
			}
			else if (p == "lopass")
			{
				mTracker.setLopass(v);
			}
			
			else if (p == "z_thresh")
			{
				mTracker.setThresh(v);
			}
			else if (p == "z_max")
			{
				mTracker.setMaxForce(v);
			}
			else if (p == "z_curve")
			{
				mTracker.setForceCurve(v);
			}
			else if (p == "snap")
			{
				sendParametersToZones();
			}
			else if (p == "vibrato")
			{
				sendParametersToZones();
			}
			else if (p == "lock")
			{
				sendParametersToZones();
			}
			else if (p == "data_freq_midi")
			{
				// TODO attribute
				mMIDIOutput.setDataFreq(v);
			}
			else if (p == "data_freq_osc")
			{
				// TODO attribute
				mOSCOutput.setDataFreq(v);
			}
			else if (p == "midi_active")
			{
				mMIDIOutput.setActive(bool(v));
			}
			else if (p == "midi_multi_chan")
			{
				mMIDIOutput.setMultiChannel(bool(v));
			}
			else if (p == "midi_start_chan")
			{
				mMIDIOutput.setStartChannel(int(v));
			}
			else if (p == "midi_pressure_active")
			{
				mMIDIOutput.setPressureActive(bool(v));
			}
			else if (p == "osc_active")
			{
				bool b = v;
				mOSCOutput.setActive(b);
				listenToOSC(b ? kDefaultUDPReceivePort : 0);
			}
			else if (p == "osc_send_matrix")
			{
				bool b = v;
				mSendMatrixData = b;
			}
			else if (p == "t_thresh")
			{
				mTracker.setTemplateThresh(v);
			}
			else if (p == "bg_filter")
			{
				mTracker.setBackgroundFilter(v);
			}
			else if (p == "quantize")
			{
				bool b = v;
				mTracker.setQuantize(b);
				sendParametersToZones();
			}
			else if (p == "rotate")
			{
				bool b = v;
				mTracker.setRotate(b);
			}
			else if (p == "retrig")
			{
				mMIDIOutput.setRetrig(bool(v));
				sendParametersToZones();
			}
			else if (p == "hysteresis")
			{
				mMIDIOutput.setHysteresis(v);
				sendParametersToZones();
			}
			else if (p == "transpose")
			{
				sendParametersToZones();
			}
			else if (p == "bend_range")
			{
				mMIDIOutput.setBendRange(v);
				sendParametersToZones();
			}
			else if (p == "debug_pause")
			{
				debug().setActive(!bool(v));
			}
			else if (p == "kyma_poll")
			{
				mMIDIOutput.setKymaPoll(bool(v));
			}
		}
			break;
		case MLProperty::kStringProperty:
		{
			const std::string& str = newVal.getStringValue();
			if (p == "viewmode")
			{
				// nothing to do for Model
			}
			else if (p == "midi_device")
			{
				mMIDIOutput.setDevice(str);
			}
			else if (p == "zone_JSON")
			{
				loadZonesFromString(str);
			}
		}
			break;
		case MLProperty::kSignalProperty:
		{
			const MLSignal& sig = newVal.getSignalValue();
			if(p == MLSymbol("carriers"))
			{
				// get carriers from signal
				assert(sig.getSize() == kSoundplaneSensorWidth);
				for(int i=0; i<kSoundplaneSensorWidth; ++i)
				{
					mCarriers[i] = sig[i];
				}
				mNeedsCarriersSet = true;
			}
			if(p == MLSymbol("tracker_calibration"))
			{
				mTracker.setCalibration(sig);
			}
			if(p == MLSymbol("tracker_normalize"))
			{
				mTracker.setNormalizeMap(sig);
			}

		}
			break;
		default:
			break;
	}
}
コード例 #18
0
void MLPluginProcessor::setStateFromXML(const XmlElement& xmlState, bool setViewAttributes)
{
	if (!(xmlState.hasTagName (JucePlugin_Name))) return;
	if (!(mEngine.getCompileStatus() == MLProc::OK)) return; // TODO revisit need to compile first

	// getCallbackLock() is in juce_AudioProcessor
	// process lock is a quick fix.  it is here to prevent doParams() from getting called in 
	// process() methods and thereby setting mParamsChanged to false before the real changes take place.
	// A better alternative would be a lock-free queue of parameter changes.
	const ScopedLock sl (getCallbackLock()); 
		
	// only the differences between default parameters and the program state are saved in a program,
	// so the first step is to set the default parameters.
	setDefaultParameters();
	
	// get program version of saved state
	unsigned blobVersion = xmlState.getIntAttribute ("pluginVersion");
	unsigned pluginVersion = JucePlugin_VersionCode;
	
	if (blobVersion > pluginVersion)
	{
		// TODO show error to user
		MLError() << "MLPluginProcessor::setStateFromXML: saved program version is newer than plugin version!\n";
		return;
	}
    
	// try to load scale if a scale attribute exists
    // TODO auto save all state including this
 	const String scaleDir = xmlState.getStringAttribute ("scaleDir"); // look for old-style dir attribute   
	const String scaleName = xmlState.getStringAttribute ("scaleName");
    String fullName;
    if(scaleName != String::empty)
    {
        fullName = scaleName;
        if(scaleDir != String::empty)
        {
            fullName = scaleDir + String("/") + fullName + ".scl";
        }
    }
    else
    {
        fullName = "12-equal";
    }
    std::string fullScaleName(fullName.toUTF8());
	setProperty("key_scale", fullScaleName);
    bool loaded = false;
    // look for scale under full name with path
    if(fullScaleName != std::string())
    {
        const MLFilePtr f = mScaleFiles->getFileByName(fullScaleName);
        if(f != MLFilePtr())
        {
            loadScale(f->mFile);
            loaded = true;
        }
    }
    if(!loaded)
    {
        loadDefaultScale();
    }
    
	// get preset name saved in blob.  when saving from AU host, name will also be set from RestoreState().
	const String presetName = xmlState.getStringAttribute ("presetName");
	setProperty("preset", std::string(presetName.toUTF8()));
    
	/*
     debug() << "MLPluginProcessor: setStateFromXML: loading program " << presetName << ", version " << std::hex << blobVersion << std::dec << "\n";
     MemoryOutputStream myStream;
     xmlState->writeToStream (myStream, "");
     debug() << myStream.toString();
     */
	
    /*
     setCurrentPresetName(presetName.toUTF8());
     setCurrentPresetDir(presetDir.toUTF8());
     */
    
	// get plugin-specific translation table for updating older versions of data
	std::map<MLSymbol, MLSymbol> translationTable;

	// TODO move this into Aalto! 
	// make translation tables based on program version. 
	//
	if (blobVersion <= 0x00010120)
	{
		// translate seq parameters
		for(unsigned n=0; n<16; ++n)
		{
			std::stringstream pName;
			std::stringstream pName2;
			pName << "seq_value" << n;
			pName2 << "seq_pulse" << n;
			MLSymbol oldSym(pName.str());
			MLSymbol newSym = MLSymbol("seq_value#").withFinalNumber(n);
			MLSymbol oldSym2(pName2.str());
			MLSymbol newSym2 = MLSymbol("seq_pulse#").withFinalNumber(n);
			translationTable[oldSym] = newSym;
			translationTable[oldSym2] = newSym2;	
		}
	}

	if (blobVersion <= 0x00010200)
	{
		MLSymbol oldSym = MLSymbol("seq_value");
		MLSymbol newSym = MLSymbol("seq_value").withFinalNumber(0);
		MLSymbol oldSym2 = MLSymbol("seq_pulse");
		MLSymbol newSym2 = MLSymbol("seq_pulse").withFinalNumber(0);
		translationTable[oldSym] = newSym;
		translationTable[oldSym2] = newSym2;
		
		// translate seq parameters
		for(unsigned n=1; n<16; ++n)
		{
			oldSym = MLSymbol("seq_value#").withFinalNumber(n);
			newSym = MLSymbol("seq_value").withFinalNumber(n);
			oldSym2 = MLSymbol("seq_pulse#").withFinalNumber(n);
			newSym2 = MLSymbol("seq_pulse").withFinalNumber(n);
			translationTable[oldSym] = newSym;
			translationTable[oldSym2] = newSym2;	
		}		
	}
	
	// get params from xml
	const unsigned numAttrs = xmlState.getNumAttributes();
	String patcherInputStr ("patcher_input_");

	for(unsigned i=0; i<numAttrs; ++i)
	{
		// get name / value pair.
		const String& attrName = xmlState.getAttributeName(i);
		const MLParamValue paramVal = xmlState.getDoubleAttribute(attrName);
		
		// if not a patcher input setting,
		if (!attrName.contains(patcherInputStr))
		{					
			// see if we have this named parameter in our engine. 
			MLSymbol paramSym = XMLAttrToSymbol(attrName);
			const int pIdx = getParameterIndex(paramSym);
			
			if (pIdx >= 0)
			{
				// debug() << "setStateFromXML: <" << paramSym << " = " << paramVal << ">\n";
				setPropertyImmediate(paramSym, paramVal);
			}
			else // try finding a match through translation table. 
			{
				//debug() << "Looking for parameter " << paramSym << " in table...\n";
				std::map<MLSymbol, MLSymbol>::iterator it;
				it = translationTable.find(paramSym);
				if (it != translationTable.end())
				{
					const MLSymbol newSym = translationTable[paramSym];
					const int pNewIdx = getParameterIndex(newSym);
					if (pNewIdx >= 0)
					{
						//debug() << "translated parameter to " << newSym << " .\n";
						setPropertyImmediate(newSym, paramVal);
					}
					else
					{
						MLError() << "MLPluginProcessor::setStateFromXML: no such parameter! \n";
					}
				}
				else
				{
					// fail silently on unfound params, because we have deprecated some but they may still 
					// be around in old presets. 
					//debug() << "MLPluginProcessor::setStateFromXML: parameter " << paramSym << " not found!\n";
				}
			}
		}
	}
	
	// get editor state from XML
    if(setViewAttributes)
	{
		int x = xmlState.getIntAttribute("editor_x");
		int y = xmlState.getIntAttribute("editor_y");
		int width = xmlState.getIntAttribute("editor_width");
		int height = xmlState.getIntAttribute("editor_height");
		mEditorRect = MLRect(x, y, width, height);
		mEditorNumbersOn = xmlState.getIntAttribute("editor_num", 1);
		mEditorAnimationsOn = xmlState.getIntAttribute("editor_anim", 1);
	}
}