view overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/SF2Instrument.java @ 843:bcba163568ac

Integrate Gervill. 2008-04-30 Mark Wielaard <mark@klomp.org> * Makefile.am (ICEDTEA_PATCHES): Add patches/icedtea-gervill.patch. * Makefile.in: Regenerated. * patches/icedtea-gervill.patch: New patch. * overlays/openjdk/jdk/src/share/classes/com/sun/media/sound/*: New Gervill files.
author Mark Wielaard <mark@klomp.org>
date Wed, 30 Apr 2008 22:09:08 +0200
parents
children
line wrap: on
line source

/*
  * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Sun designates this
  * particular file as subject to the "Classpath" exception as provided
  * by Sun in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * version 2 for more details (a copy is included in the LICENSE file that
  * accompanied this code).
  *
  * You should have received a copy of the GNU General Public License version
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  * CA 95054 USA or visit www.sun.com if you need additional information or
  * have any questions.
  */ 

package com.sun.media.sound;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sound.midi.Patch;

/**
 * Soundfont instrument.
 * 
 * @version %I%, %E%
 * @author Karl Helgason
 */ 
public class SF2Instrument extends ModelInstrument {

	protected String name = "";
	protected int preset = 0;
	protected int bank = 0;
	protected long library = 0;
	protected long genre = 0;
	protected long morphology = 0;
	
	protected SF2GlobalRegion globalregion = null;
	
	protected List<SF2InstrumentRegion> regions = new ArrayList<SF2InstrumentRegion>();

	public SF2Instrument() {
		super(null, null, null, null);
	}
	
	public SF2Instrument(SF2Soundbank soundbank) {
		super(soundbank, null, null, null);
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name)
	{
		this.name = name;
	}
		
	public Patch getPatch() {
		if(bank == 128)
			return new ModelPatch(0, preset, true);
		else
			return new ModelPatch(bank << 7, preset, false);
	}
	
	public void setPatch(Patch patch)
	{
		if(patch instanceof ModelPatch && ((ModelPatch)patch).isPercussion())
		{
			bank = 128;
			preset = patch.getProgram();			
		}
		else
		{
			bank = patch.getBank() >> 7;
			preset = patch.getProgram();
		}
	}

	public Object getData() {
		return null;
	}

	public long getGenre() {
		return genre;
	}

	public void setGenre(long genre) {
		this.genre = genre;
	}

	public long getLibrary() {
		return library;
	}

	public void setLibrary(long library) {
		this.library = library;
	}

	public long getMorphology() {
		return morphology;
	}

	public void setMorphology(long morphology) {
		this.morphology = morphology;
	}

	public List<SF2InstrumentRegion> getRegions() {
		return regions;
	}
	
	public SF2GlobalRegion getGlobalRegion()
	{
		return globalregion;
	}
	
	public void setGlobalZone(SF2GlobalRegion zone)
	{
		globalregion = zone;
	}	
	
	public String toString()
	{
		if(bank == 128)
			return "Drumkit: " + name + " preset #" + preset;
		else
			return "Instrument: " + name + " bank #" + bank + " preset #" + preset; 
	}

	public ModelPerformer[] getPerformers() {
		int performercount = 0;
		for(SF2InstrumentRegion presetzone : regions)
			performercount += presetzone.getLayer().getRegions().size();		
		ModelPerformer[] performers = new ModelPerformer[performercount];
		int pi = 0;
		
		SF2GlobalRegion presetglobal = globalregion;		
		for(SF2InstrumentRegion presetzone : regions)
		{			
			Map<Integer, Short> pgenerators = new HashMap<Integer, Short>();
			pgenerators.putAll(presetzone.getGenerators());
			if(presetglobal != null)
			pgenerators.putAll(presetglobal.getGenerators());
			
			SF2Layer layer = presetzone.getLayer();
			SF2GlobalRegion layerglobal = layer.getGlobalRegion();
			for(SF2LayerRegion layerzone : layer.getRegions())
			{
				ModelPerformer performer = new ModelPerformer();
				if(layerzone.getSample() != null)
				{
					performer.setName(layerzone.getSample().getName());
				}
				else
					performer.setName(layer.getName());
				
				performers[pi++] = performer;				
								
				int keyfrom = 0;
				int keyto = 127;
				int velfrom = 0;
				int velto = 127;
				
				if(layerzone.contains(SF2Region.GENERATOR_EXCLUSIVECLASS))
				{
					performer.setExclusiveClass(layerzone.getInteger(SF2Region.GENERATOR_EXCLUSIVECLASS));					
				}				
				if(layerzone.contains(SF2Region.GENERATOR_KEYRANGE))
				{
					byte[] bytes = layerzone.getBytes(SF2Region.GENERATOR_KEYRANGE);
					if(bytes[0] >= 0)
						if(bytes[0] > keyfrom) keyfrom = bytes[0];
					if(bytes[1] >= 0)
						if(bytes[1] < keyto) keyto = bytes[1];
				}
				if(layerzone.contains(SF2Region.GENERATOR_VELRANGE))
				{
					byte[] bytes = layerzone.getBytes(SF2Region.GENERATOR_VELRANGE);
					if(bytes[0] >= 0)
						if(bytes[0] > velfrom) velfrom = bytes[0];
					if(bytes[1] >= 0)
						if(bytes[1] < velto) velto = bytes[1];
				}
				if(presetzone.contains(SF2Region.GENERATOR_KEYRANGE))
				{
					byte[] bytes = presetzone.getBytes(SF2Region.GENERATOR_KEYRANGE);
					if(bytes[0] > keyfrom) keyfrom = bytes[0];
					if(bytes[1] < keyto) keyto = bytes[1];
				}
				if(presetzone.contains(SF2Region.GENERATOR_VELRANGE))
				{
					byte[] bytes = presetzone.getBytes(SF2Region.GENERATOR_VELRANGE);
					if(bytes[0] > velfrom) velfrom = bytes[0];
					if(bytes[1] < velto) velto = bytes[1];
				}				
				performer.setKeyFrom(keyfrom);
				performer.setKeyTo(keyto);
				performer.setVelFrom(velfrom);				
				performer.setVelTo(velto);
															
				int startAddrsOffset = layerzone.getShort(SF2Region.GENERATOR_STARTADDRSOFFSET);
				int endAddrsOffset = layerzone.getShort(SF2Region.GENERATOR_ENDADDRSOFFSET);					
				int startloopAddrsOffset = layerzone.getShort(SF2Region.GENERATOR_STARTLOOPADDRSOFFSET);
				int endloopAddrsOffset = layerzone.getShort(SF2Region.GENERATOR_ENDLOOPADDRSOFFSET);
				
				startAddrsOffset +=  layerzone.getShort(SF2Region.GENERATOR_STARTADDRSCOARSEOFFSET) *32768;
				endAddrsOffset +=  layerzone.getShort(SF2Region.GENERATOR_ENDADDRSCOARSEOFFSET) *32768;					
				startloopAddrsOffset +=  layerzone.getShort(SF2Region.GENERATOR_STARTLOOPADDRSCOARSEOFFSET) *32768;
				endloopAddrsOffset +=  layerzone.getShort(SF2Region.GENERATOR_ENDLOOPADDRSCOARSEOFFSET) *32768;
				startloopAddrsOffset -= startAddrsOffset;
				endloopAddrsOffset -= startAddrsOffset;
								
				SF2Sample sample = layerzone.getSample();
				int rootkey = sample.originalPitch;
				if(layerzone.getShort(SF2Region.GENERATOR_OVERRIDINGROOTKEY) != -1)
					rootkey = layerzone.getShort(SF2Region.GENERATOR_OVERRIDINGROOTKEY);
				float pitchcorrection = (-rootkey*100) + sample.pitchCorrection;
				ModelByteBuffer buff = sample.getDataBuffer();
				ModelByteBuffer buff24 = sample.getData24Buffer();
				
				if(startAddrsOffset != 0 || endAddrsOffset != 0)
				{
					buff = buff.subbuffer(startAddrsOffset*2, buff.capacity() + endAddrsOffset*2);
					if(buff24 != null)
						buff24 = buff24.subbuffer(startAddrsOffset, buff24.capacity() + endAddrsOffset);
						
					/*
					if(startAddrsOffset < 0) startAddrsOffset = 0;
					if(endAddrsOffset > (buff.capacity()/2-startAddrsOffset)) startAddrsOffset = (int)buff.capacity()/2-startAddrsOffset;
					byte[] data = buff.array();
					int off = (int)buff.arrayOffset() + startAddrsOffset*2;
					int len = (int)buff.capacity() + endAddrsOffset*2;
					if(off+len > data.length) len = data.length - off;
					buff = new ModelByteBuffer(data, off, len);
					if(buff24 != null)
					{
						data = buff.array();
						off = (int)buff.arrayOffset() + startAddrsOffset;
						len = (int)buff.capacity() + endAddrsOffset;
						buff24 = new ModelByteBuffer(data, off, len);
					} */
				}

				ModelByteBufferWavetable osc = new ModelByteBufferWavetable(buff, sample.getFormat(),pitchcorrection);
				if(buff24 != null) osc.set8BitExtensionBuffer(buff24);
												
				Map<Integer, Short> generators = new HashMap<Integer, Short>();
				if(layerglobal != null)
				generators.putAll(layerglobal.getGenerators());
				generators.putAll(layerzone.getGenerators());				
				for(Map.Entry<Integer,Short> gen : pgenerators.entrySet())
				{
					short val;
					if(!generators.containsKey(gen.getKey()))						
						val = layerzone.getShort(gen.getKey());
					else
						val = generators.get(gen.getKey());
					val += gen.getValue();
					generators.put(gen.getKey(), val);
				}
				
				// SampleMode:
				// 0 indicates a sound reproduced with no loop
				// 1 indicates a sound which loops continuously
				// 2 is unused but should be interpreted as indicating no loop
				// 3 indicates a sound which loops for the duration of key depression then proceeds to play the remainder of the sample.
				int sampleMode = getGeneratorValue(generators, SF2Region.GENERATOR_SAMPLEMODES);				
				if((sampleMode == 1) || (sampleMode == 3))
				if(sample.startLoop >= 0 && sample.endLoop > 0)
				{
					osc.setLoopStart((int)(sample.startLoop+startloopAddrsOffset));
					osc.setLoopLength((int)(sample.endLoop - sample.startLoop+endloopAddrsOffset - startloopAddrsOffset));
					if(sampleMode == 1) osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD);
					if(sampleMode == 3) osc.setLoopType(ModelWavetable.LOOP_TYPE_RELEASE);
				}
				performer.getOscillators().add(osc);
				
				
				short volDelay = getGeneratorValue(generators, SF2Region.GENERATOR_DELAYVOLENV);
				short volAttack = getGeneratorValue(generators, SF2Region.GENERATOR_ATTACKVOLENV);
				short volHold = getGeneratorValue(generators, SF2Region.GENERATOR_HOLDVOLENV);
				short volDecay = getGeneratorValue(generators, SF2Region.GENERATOR_DECAYVOLENV);
				short volSustain = getGeneratorValue(generators, SF2Region.GENERATOR_SUSTAINVOLENV);
				short volRelease = getGeneratorValue(generators, SF2Region.GENERATOR_RELEASEVOLENV);
				
				if(volHold != -12000)
				{								
					short volKeyNumToHold = getGeneratorValue(generators, SF2Region.GENERATOR_KEYNUMTOVOLENVHOLD);					
					volHold += 60*volKeyNumToHold;
					float fvalue = -volKeyNumToHold*128; 
					ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
					ModelIdentifier dest = ModelDestination.DESTINATION_EG1_HOLD;
					performer.getConnectionBlocks().add(
							new ModelConnectionBlock(new ModelSource(src), fvalue, new ModelDestination(dest)));					
				}
				if(volDecay != -12000)
				{
					short volKeyNumToDecay = getGeneratorValue(generators, SF2Region.GENERATOR_KEYNUMTOVOLENVDECAY);					
					volDecay += 60*volKeyNumToDecay;
					float fvalue = -volKeyNumToDecay*128; 
					ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
					ModelIdentifier dest = ModelDestination.DESTINATION_EG1_DECAY;
					performer.getConnectionBlocks().add(
							new ModelConnectionBlock(new ModelSource(src), fvalue, new ModelDestination(dest)));					
				}
				
				addTimecentValue(performer, ModelDestination.DESTINATION_EG1_DELAY, volDelay);
				addTimecentValue(performer, ModelDestination.DESTINATION_EG1_ATTACK, volAttack);
				addTimecentValue(performer, ModelDestination.DESTINATION_EG1_HOLD, volHold);
				addTimecentValue(performer, ModelDestination.DESTINATION_EG1_DECAY, volDecay);
				//float fvolsustain = (960-volSustain)*(1000.0f/960.0f);
				
				volSustain = (short)(1000 - volSustain);
				if(volSustain < 0) volSustain = 0;
				if(volSustain > 1000) volSustain = 1000;
				
				addValue(performer, ModelDestination.DESTINATION_EG1_SUSTAIN, volSustain);
				addTimecentValue(performer, ModelDestination.DESTINATION_EG1_RELEASE, volRelease);
				
				if(getGeneratorValue(generators, SF2Region.GENERATOR_MODENVTOFILTERFC) != 0
				|| getGeneratorValue(generators, SF2Region.GENERATOR_MODENVTOPITCH) != 0)
				{
					short modDelay = getGeneratorValue(generators, SF2Region.GENERATOR_DELAYMODENV);
					short modAttack = getGeneratorValue(generators, SF2Region.GENERATOR_ATTACKMODENV);
					short modHold = getGeneratorValue(generators, SF2Region.GENERATOR_HOLDMODENV);
					short modDecay = getGeneratorValue(generators, SF2Region.GENERATOR_DECAYMODENV);
					short modSustain = getGeneratorValue(generators, SF2Region.GENERATOR_SUSTAINMODENV);
					short modRelease = getGeneratorValue(generators, SF2Region.GENERATOR_RELEASEMODENV);
	
					
					if(modHold != -12000)
					{								
						short modKeyNumToHold = getGeneratorValue(generators, SF2Region.GENERATOR_KEYNUMTOMODENVHOLD);					
						modHold += 60*modKeyNumToHold;
						float fvalue = -modKeyNumToHold*128; 
						ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
						ModelIdentifier dest = ModelDestination.DESTINATION_EG2_HOLD;
						performer.getConnectionBlocks().add(
								new ModelConnectionBlock(new ModelSource(src), fvalue, new ModelDestination(dest)));					
					}
					if(modDecay != -12000)
					{
						short modKeyNumToDecay = getGeneratorValue(generators, SF2Region.GENERATOR_KEYNUMTOMODENVDECAY);					
						modDecay += 60*modKeyNumToDecay;
						float fvalue = -modKeyNumToDecay*128; 
						ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
						ModelIdentifier dest = ModelDestination.DESTINATION_EG2_DECAY;
						performer.getConnectionBlocks().add(
								new ModelConnectionBlock(new ModelSource(src), fvalue, new ModelDestination(dest)));					
					}
					
					addTimecentValue(performer, ModelDestination.DESTINATION_EG2_DELAY, modDelay);
					addTimecentValue(performer, ModelDestination.DESTINATION_EG2_ATTACK, modAttack);
					addTimecentValue(performer, ModelDestination.DESTINATION_EG2_HOLD, modHold);
					addTimecentValue(performer, ModelDestination.DESTINATION_EG2_DECAY, modDecay);
					if(modSustain < 0) modSustain = 0;
					if(modSustain > 1000) modSustain = 1000;
					addValue(performer, ModelDestination.DESTINATION_EG2_SUSTAIN, 1000 - modSustain);
					addTimecentValue(performer, ModelDestination.DESTINATION_EG2_RELEASE, modRelease);
					
					if(getGeneratorValue(generators, SF2Region.GENERATOR_MODENVTOFILTERFC) != 0)
					{
						double fvalue = getGeneratorValue(generators, SF2Region.GENERATOR_MODENVTOFILTERFC);
						ModelIdentifier src = ModelSource.SOURCE_EG2;
						ModelIdentifier dest = ModelDestination.DESTINATION_FILTER_FREQ;
						performer.getConnectionBlocks().add(
								new ModelConnectionBlock(new ModelSource(src), fvalue, new ModelDestination(dest)));
					}
					
					if(getGeneratorValue(generators, SF2Region.GENERATOR_MODENVTOPITCH) != 0)
					{
						double fvalue = getGeneratorValue(generators, SF2Region.GENERATOR_MODENVTOPITCH);
						ModelIdentifier src = ModelSource.SOURCE_EG2;
						ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
						performer.getConnectionBlocks().add(
								new ModelConnectionBlock(new ModelSource(src), fvalue, new ModelDestination(dest)));
					}
					
				}
				
				if(getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOFILTERFC) != 0
				  || getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOPITCH) != 0
			      || getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOVOLUME) != 0)
				{
					short lfo_freq = getGeneratorValue(generators, SF2Region.GENERATOR_FREQMODLFO);
					short lfo_delay = getGeneratorValue(generators, SF2Region.GENERATOR_DELAYMODLFO);
					addTimecentValue(performer, ModelDestination.DESTINATION_LFO1_DELAY, lfo_delay);
					addValue(performer, ModelDestination.DESTINATION_LFO1_FREQ, lfo_freq);
				}
				
				short vib_freq = getGeneratorValue(generators, SF2Region.GENERATOR_FREQVIBLFO);
				short vib_delay = getGeneratorValue(generators, SF2Region.GENERATOR_DELAYVIBLFO);
				addTimecentValue(performer, ModelDestination.DESTINATION_LFO2_DELAY, vib_delay);
				addValue(performer, ModelDestination.DESTINATION_LFO2_FREQ, vib_freq);
				
				
				if(getGeneratorValue(generators, SF2Region.GENERATOR_VIBLFOTOPITCH) != 0)
				{
					double fvalue = getGeneratorValue(generators, SF2Region.GENERATOR_VIBLFOTOPITCH);
					ModelIdentifier src = ModelSource.SOURCE_LFO2;
					ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
					performer.getConnectionBlocks().add(
							new ModelConnectionBlock(new ModelSource(src,ModelStandardTransform.DIRECTION_MIN2MAX,ModelStandardTransform.POLARITY_BIPOLAR), fvalue, new ModelDestination(dest)));
				}				
				
				if(getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOFILTERFC) != 0)
				{
					double fvalue = getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOFILTERFC);
					ModelIdentifier src = ModelSource.SOURCE_LFO1;
					ModelIdentifier dest = ModelDestination.DESTINATION_FILTER_FREQ;
					performer.getConnectionBlocks().add(
							new ModelConnectionBlock(new ModelSource(src,ModelStandardTransform.DIRECTION_MIN2MAX,ModelStandardTransform.POLARITY_BIPOLAR), fvalue, new ModelDestination(dest)));
				}				

				if(getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOPITCH) != 0)
				{
					double fvalue = getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOPITCH);
					ModelIdentifier src = ModelSource.SOURCE_LFO1;
					ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
					performer.getConnectionBlocks().add(
							new ModelConnectionBlock(new ModelSource(src,ModelStandardTransform.DIRECTION_MIN2MAX,ModelStandardTransform.POLARITY_BIPOLAR), fvalue, new ModelDestination(dest)));
				}
				
				if(getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOVOLUME) != 0)
				{
					double fvalue = getGeneratorValue(generators, SF2Region.GENERATOR_MODLFOTOVOLUME);
					ModelIdentifier src = ModelSource.SOURCE_LFO1;
					ModelIdentifier dest = ModelDestination.DESTINATION_GAIN;
					performer.getConnectionBlocks().add(
							new ModelConnectionBlock(new ModelSource(src,ModelStandardTransform.DIRECTION_MIN2MAX,ModelStandardTransform.POLARITY_BIPOLAR), fvalue, new ModelDestination(dest)));
				}
				
				if(layerzone.getShort(SF2Region.GENERATOR_KEYNUM) != -1)
				{
					double val = layerzone.getShort(SF2Region.GENERATOR_KEYNUM)/128.0;
					addValue(performer, ModelDestination.DESTINATION_KEYNUMBER, val);
				}
				
				if(layerzone.getShort(SF2Region.GENERATOR_VELOCITY) != -1)
				{
					double val = layerzone.getShort(SF2Region.GENERATOR_VELOCITY)/128.0;
					addValue(performer, ModelDestination.DESTINATION_VELOCITY, val);
				}
				
				if(getGeneratorValue(generators, SF2Region.GENERATOR_INITIALFILTERFC) < 13500)
				{
					short filter_freq = getGeneratorValue(generators, SF2Region.GENERATOR_INITIALFILTERFC);
					short filter_q = getGeneratorValue(generators, SF2Region.GENERATOR_INITIALFILTERQ);
					addValue(performer, ModelDestination.DESTINATION_FILTER_FREQ, filter_freq);
					addValue(performer, ModelDestination.DESTINATION_FILTER_Q, filter_q);
				}
				
				int tune = 100 * getGeneratorValue(generators, SF2Region.GENERATOR_COARSETUNE);
				tune += getGeneratorValue(generators, SF2Region.GENERATOR_FINETUNE);
				if(tune != 0)
				{
					addValue(performer, ModelDestination.DESTINATION_PITCH, (short)tune);
				}
				if(getGeneratorValue(generators, SF2Region.GENERATOR_PAN) != 0)
				{
					short val = getGeneratorValue(generators, SF2Region.GENERATOR_PAN);
					addValue(performer, ModelDestination.DESTINATION_PAN, val);
				}
				if(getGeneratorValue(generators, SF2Region.GENERATOR_INITIALATTENUATION) != 0)
				{
					short val = getGeneratorValue(generators, SF2Region.GENERATOR_INITIALATTENUATION);
					addValue(performer, ModelDestination.DESTINATION_GAIN, -0.376287f*val);
				}
				if(getGeneratorValue(generators, SF2Region.GENERATOR_CHORUSEFFECTSSEND) != 0)
				{
					short val = getGeneratorValue(generators, SF2Region.GENERATOR_CHORUSEFFECTSSEND);
					addValue(performer, ModelDestination.DESTINATION_CHORUS, val);
				}
				if(getGeneratorValue(generators, SF2Region.GENERATOR_REVERBEFFECTSSEND) != 0)
				{
					short val = getGeneratorValue(generators, SF2Region.GENERATOR_REVERBEFFECTSSEND);
					addValue(performer, ModelDestination.DESTINATION_REVERB, val);
				}
				if(getGeneratorValue(generators, SF2Region.GENERATOR_SCALETUNING) != 100)
				{
					short fvalue = getGeneratorValue(generators, SF2Region.GENERATOR_SCALETUNING);
					if(fvalue == 0)
					{						
						ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
						performer.getConnectionBlocks().add(
							new ModelConnectionBlock(null, rootkey * 100, new ModelDestination(dest)));
					}
					else
					{						
						ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
						performer.getConnectionBlocks().add(
							new ModelConnectionBlock(null, rootkey * (100 - fvalue), new ModelDestination(dest)));
					}		
					
					ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
					ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
					performer.getConnectionBlocks().add(
						new ModelConnectionBlock(new ModelSource(src), 128*fvalue, new ModelDestination(dest)));
					
				}
			
				performer.getConnectionBlocks().add(new ModelConnectionBlock(
						new ModelSource(ModelSource.SOURCE_NOTEON_VELOCITY,
								new ModelTransform()
								{
									public double transform(double value) {
										if(value < 0.5)
										{
											return 1 - value*2;
										}
										else
											return 0;
									}
								}
						)
						,-2400,new ModelDestination(ModelDestination.DESTINATION_FILTER_FREQ)));					

				
				performer.getConnectionBlocks().add(new ModelConnectionBlock(
						new ModelSource(ModelSource.SOURCE_LFO2,
						ModelStandardTransform.DIRECTION_MIN2MAX,ModelStandardTransform.POLARITY_BIPOLAR,ModelStandardTransform.TRANSFORM_LINEAR),
						new ModelSource(new ModelIdentifier("midi_cc","1",0),
						ModelStandardTransform.DIRECTION_MIN2MAX,ModelStandardTransform.POLARITY_UNIPOLAR,ModelStandardTransform.TRANSFORM_LINEAR),
						50,new ModelDestination(ModelDestination.DESTINATION_PITCH)));					
				
				if(layer.getGlobalRegion() != null)
					for(SF2Modulator modulator : layer.getGlobalRegion().getModulators())
						convertModulator(performer, modulator);
				for(SF2Modulator modulator : layerzone.getModulators())
					convertModulator(performer, modulator);

				if(presetglobal != null)
					for(SF2Modulator modulator : presetglobal.getModulators())
						convertModulator(performer, modulator);
				for(SF2Modulator modulator : presetzone.getModulators())
					convertModulator(performer, modulator);

				
				
				
			}
		}
		return performers;
	}
	
	private void convertModulator(ModelPerformer performer, SF2Modulator modulator)
	{
		ModelSource src1 = convertSource(modulator.getSourceOperator());
		ModelSource src2 = convertSource(modulator.getAmountSourceOperator());
		if(src1 == null && modulator.getSourceOperator() != 0) return;
		if(src2 == null && modulator.getAmountSourceOperator() != 0) return;
		double amount = modulator.getAmount();
		double[] amountcorrection = new double[1];
		ModelSource[] extrasrc = new ModelSource[1]; 
		amountcorrection[0] = 1;
		ModelDestination dst = convertDestination(modulator.getDestinationOperator(), amountcorrection, extrasrc);			
		amount *= amountcorrection[0];
		if(dst == null) return;
		if(modulator.getTransportOperator() == SF2Modulator.TRANSFORM_ABSOLUTE) 
			((ModelStandardTransform)dst.getTransform()).setTransform(ModelStandardTransform.TRANSFORM_ABSOLUTE);				
		ModelConnectionBlock conn = new ModelConnectionBlock(src1,src2,amount,dst);
		if(extrasrc[0] != null) conn.addSource(extrasrc[0]);
		performer.getConnectionBlocks().add(conn);
		
		
	}
	
	private static ModelSource convertSource(int src)
	{
		if(src == 0) return null;
		ModelIdentifier id = null;
		int idsrc = src & 0x7F;
		if((src & SF2Modulator.SOURCE_MIDI_CONTROL) != 0)
		{
			id = new ModelIdentifier("midi_cc", Integer.toString(idsrc));
		}
		else
		{
			if(idsrc == SF2Modulator.SOURCE_NOTE_ON_VELOCITY)
				id = ModelSource.SOURCE_NOTEON_VELOCITY;
			if(idsrc == SF2Modulator.SOURCE_NOTE_ON_KEYNUMBER)
				id = ModelSource.SOURCE_NOTEON_KEYNUMBER;			
			if(idsrc == SF2Modulator.SOURCE_POLY_PRESSURE)
				id = ModelSource.SOURCE_MIDI_POLY_PRESSURE;
			if(idsrc == SF2Modulator.SOURCE_CHANNEL_PRESSURE)
				id = ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE;			
			if(idsrc == SF2Modulator.SOURCE_PITCH_WHEEL)
				id = ModelSource.SOURCE_MIDI_PITCH;
			if(idsrc == SF2Modulator.SOURCE_PITCH_SENSITIVITY)
				id = new ModelIdentifier("midi_rpn", "0");

		}
		if(id == null) return null;
		
		ModelSource msrc = new ModelSource(id);		
		ModelStandardTransform transform = (ModelStandardTransform)msrc.getTransform();
				
		if((SF2Modulator.SOURCE_DIRECTION_MAX_MIN & src) != 0)
			transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN);
		else
			transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX);

		if((SF2Modulator.SOURCE_POLARITY_BIPOLAR & src) != 0)
			transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR);
		else
			transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR);
		
		if((SF2Modulator.SOURCE_TYPE_CONCAVE & src) != 0)
			transform.setTransform(ModelStandardTransform.TRANSFORM_CONCAVE);
		if((SF2Modulator.SOURCE_TYPE_CONVEX & src) != 0)
			transform.setTransform(ModelStandardTransform.TRANSFORM_CONVEX);
		if((SF2Modulator.SOURCE_TYPE_SWITCH & src) != 0)
			transform.setTransform(ModelStandardTransform.TRANSFORM_SWITCH);
		
		return msrc;
	}
	
	protected static ModelDestination convertDestination(int dst, double[] amountcorrection, ModelSource[] extrasrc)
	{
		ModelIdentifier id = null; 
		switch (dst) {
		case SF2Region.GENERATOR_INITIALFILTERFC :
			id = ModelDestination.DESTINATION_FILTER_FREQ;
			break;
		case SF2Region.GENERATOR_INITIALFILTERQ  :
			id = ModelDestination.DESTINATION_FILTER_Q;
			break;			
		case SF2Region.GENERATOR_CHORUSEFFECTSSEND   :
			id = ModelDestination.DESTINATION_CHORUS;
			break;
		case SF2Region.GENERATOR_REVERBEFFECTSSEND   :
			id = ModelDestination.DESTINATION_REVERB;
			break;			
		case SF2Region.GENERATOR_PAN  :
			id = ModelDestination.DESTINATION_PAN;
			break;		
		case SF2Region.GENERATOR_DELAYMODLFO  :
			id = ModelDestination.DESTINATION_LFO1_DELAY;
			break;			
		case SF2Region.GENERATOR_FREQMODLFO   :
			id = ModelDestination.DESTINATION_LFO1_FREQ;
			break;			
		case SF2Region.GENERATOR_DELAYVIBLFO   :
			id = ModelDestination.DESTINATION_LFO2_DELAY;
			break;			
		case SF2Region.GENERATOR_FREQVIBLFO    :
			id = ModelDestination.DESTINATION_LFO2_FREQ;
			break;
			
			
			
		case SF2Region.GENERATOR_DELAYMODENV    :
			id = ModelDestination.DESTINATION_EG2_DELAY;
			break;						
		case SF2Region.GENERATOR_ATTACKMODENV    :
			id = ModelDestination.DESTINATION_EG2_ATTACK;
			break;						
		case SF2Region.GENERATOR_HOLDMODENV    :
			id = ModelDestination.DESTINATION_EG2_HOLD;
			break;						
		case SF2Region.GENERATOR_DECAYMODENV    :
			id = ModelDestination.DESTINATION_EG2_DECAY;
			break;						
		case SF2Region.GENERATOR_SUSTAINMODENV    :
			id = ModelDestination.DESTINATION_EG2_SUSTAIN;
			amountcorrection[0] = -1;
			break;						
		case SF2Region.GENERATOR_RELEASEMODENV    :
			id = ModelDestination.DESTINATION_EG2_RELEASE;
			break;									
		case SF2Region.GENERATOR_DELAYVOLENV    :
			id = ModelDestination.DESTINATION_EG1_DELAY;
			break;						
		case SF2Region.GENERATOR_ATTACKVOLENV    :
			id = ModelDestination.DESTINATION_EG1_ATTACK;
			break;						
		case SF2Region.GENERATOR_HOLDVOLENV    :
			id = ModelDestination.DESTINATION_EG1_HOLD;
			break;						
		case SF2Region.GENERATOR_DECAYVOLENV    :
			id = ModelDestination.DESTINATION_EG1_DECAY;
			break;						
		case SF2Region.GENERATOR_SUSTAINVOLENV    :
			id = ModelDestination.DESTINATION_EG1_SUSTAIN;
			amountcorrection[0] = -1;
			break;						
		case SF2Region.GENERATOR_RELEASEVOLENV    :
			id = ModelDestination.DESTINATION_EG1_RELEASE;
			break;														
		case SF2Region.GENERATOR_KEYNUM     :
			id = ModelDestination.DESTINATION_KEYNUMBER;
			break;									
		case SF2Region.GENERATOR_VELOCITY     :
			id = ModelDestination.DESTINATION_VELOCITY;
			break;									

		case SF2Region.GENERATOR_COARSETUNE       :
			amountcorrection[0] = 100;
			id = ModelDestination.DESTINATION_PITCH;
			break;									

		case SF2Region.GENERATOR_FINETUNE        :
			id = ModelDestination.DESTINATION_PITCH;
			break;									

		case SF2Region.GENERATOR_INITIALATTENUATION      :
			id = ModelDestination.DESTINATION_GAIN;
			amountcorrection[0] = -0.376287f;
			break;									

		case SF2Region.GENERATOR_VIBLFOTOPITCH         :
			id = ModelDestination.DESTINATION_PITCH;
			extrasrc[0] = new ModelSource(
					ModelSource.SOURCE_LFO2, 
					ModelStandardTransform.DIRECTION_MIN2MAX, 
					ModelStandardTransform.POLARITY_BIPOLAR);	
			break;	
			
		case SF2Region.GENERATOR_MODLFOTOPITCH          :
			id = ModelDestination.DESTINATION_PITCH;
			extrasrc[0] = new ModelSource(
					ModelSource.SOURCE_LFO1, 
					ModelStandardTransform.DIRECTION_MIN2MAX, 
					ModelStandardTransform.POLARITY_BIPOLAR);		
			break;			
			
		case SF2Region.GENERATOR_MODLFOTOFILTERFC          :
			id = ModelDestination.DESTINATION_FILTER_FREQ;
			extrasrc[0] = new ModelSource(
					ModelSource.SOURCE_LFO1, 
					ModelStandardTransform.DIRECTION_MIN2MAX, 
					ModelStandardTransform.POLARITY_BIPOLAR);		
			break;		
			
		case SF2Region.GENERATOR_MODLFOTOVOLUME           :
			id = ModelDestination.DESTINATION_GAIN;
			amountcorrection[0] = -0.376287f;
			extrasrc[0] = new ModelSource(
					ModelSource.SOURCE_LFO1, 
					ModelStandardTransform.DIRECTION_MIN2MAX, 
					ModelStandardTransform.POLARITY_BIPOLAR);		
			break;			
			
		case SF2Region.GENERATOR_MODENVTOPITCH           :
			id = ModelDestination.DESTINATION_PITCH;
			extrasrc[0] = new ModelSource(
					ModelSource.SOURCE_EG2, 
					ModelStandardTransform.DIRECTION_MIN2MAX, 
					ModelStandardTransform.POLARITY_BIPOLAR);					
			break;			
			
		case SF2Region.GENERATOR_MODENVTOFILTERFC           :
			id = ModelDestination.DESTINATION_FILTER_FREQ;
			extrasrc[0] = new ModelSource(
					ModelSource.SOURCE_EG2, 
					ModelStandardTransform.DIRECTION_MIN2MAX, 
					ModelStandardTransform.POLARITY_BIPOLAR);		
			break;		
						
			
		default:		
			break;
		}
		if(id != null) return new ModelDestination(id);
		return null;
	}	
	
	private void addTimecentValue(ModelPerformer performer, ModelIdentifier dest, short value)
	{
		double fvalue;
		if(value == -12000) 
			fvalue = Double.NEGATIVE_INFINITY;
		else
			fvalue = value;
		performer.getConnectionBlocks().add(new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
	}
	
	private void addValue(ModelPerformer performer, ModelIdentifier dest, short value)
	{
		double fvalue = value;
		performer.getConnectionBlocks().add(new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
	}
	
	private void addValue(ModelPerformer performer, ModelIdentifier dest, double value)
	{
		double fvalue = value;
		performer.getConnectionBlocks().add(new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
	}
	
	private short getGeneratorValue(Map<Integer, Short> generators, int gen)
	{
		if(generators.containsKey(gen)) return generators.get(gen);
		return SF2Region.getDefaultValue(gen);
	}
	
}