DecentSampler: File Format Reference Guide

Document Version: 1.5.24

Table of Contents


Introduction

At its core each DecentSampler sample library consists of two things: a folder containing a bunch of assets like audio files and pictures, and a single text file (called a dspreset file) which describes how the engine should use all of those files. This reference document is a guide to creating dspreset files.

dspreset files are just XML files. As such, each one begins with an XML declaration:

<?xml version="1.0" encoding="UTF-8"?>

The top-level <DecentSampler> element (required)

At the top level of every dspreset file is a <DecentSampler> element. Every file must have one. Here is a list of attributes:

Example:

<?xml version="1.0" encoding="UTF-8"?>
<DecentSampler minVersion="1.0.0">
    <!-- More tags go here. :) -->
</DecentSampler>

Underneath the top-level <DecentSampler> element you can put any number of other elements, which are described below:

The <ui> element (optional)

The <ui> element is how you specify a user interface for your instrument. Each dspreset should have at most one <ui> element. There are several important attributes:

Example:

<DecentSampler>
  <ui width="812" height="375">
    <tab name="main">
      <labeled-knob x="560" y="0" label="Tone" type="float" minValue="60" maxValue="22000"
                    textColor="FF000000" value="22000.0" uid="y8AA4uuURh3">
        <binding type="effect" level="instrument" position="0" parameter="FX_FILTER_FREQUENCY"/>
      </labeled-knob>
      <label x="360" y="0" width="50" height="30" text="Reverb"/>
      <control x="360" y="30" parameterName="Reverb" type="float" minValue="0" maxValue="1" textColor="FF000000" value="0.5">
      <!-- Your <binding /> elements should go here -->
      </control>
    </tab>
  </ui>
</DecentSampler>

The <tab> element

The <tab> element lives underneath the <ui> element. This architecture was chosen because we may, at some point, add support for multiple tabs. At present it is only possible to have a single tab within DecentSampler instruments. As such, every UI must have at most one <tab> element.

Attributes:

The <image> element

The <image> element allows you to place a static image into your user interface. It lives underneath the <tab> element. Attributes:

The <label> element

The <label> element allows you to place a static block of text into yoru user interface. It lives underneath the <tab> element. Attributes:

A label’s text can also be set dynamically using bindings using the TEXT binding parameter name.

The <labeled-knob> and <control> elements

The <labeled-knob> and <control> elements live underneath the <tab> element. These tags correspond to user controls (usually round radial dials) that can be used as part of a UI. These two element types are the same except that <labeled-knob> elements contain built-in labels, where as <control> elements do not. Every tab can have many <control> or <labeled-knob> elements underneath it.

For precise UI creation, it may be advisable to use a combination of <control> & <label> elements rather than <labeled-knob>.

Attributes:

Example:

<DecentSampler>
  <ui>
    <tab>
      <labeled-knob x="560" y="0" label="Tone" type="float" minValue="60" maxValue="22000" textColor="FF000000" value="22000.0">
      <!-- Your <binding /> elements should go here -->
      </labeled-knob>
      <label x="360" y="0" width="50" height="30" text="Reverb"/>
      <control x="360" y="30" parameterName="Reverb" type="float" minValue="0" maxValue="1" textColor="FF000000" value="0.5">
      <!-- Your <binding /> elements should go here -->
      </control>
    </tab>
  </ui>
</DecentSampler>

To learn how to make knobs actually control parameters of your instrument, see “Appendix B: Bindings” section below.

The <menu> element

The <menu> element allows you to create a drop-down menu within your UI.

Attributes:

Attribute Required Description
x (required) The x position of the menu
y (required) The y position of the menu
width (required) The width of the menu
height (required) The height of the menu
value (optional) The is the 1-based index of the menu option that is currently selected. NOTE: Index numbers for menu items start at 1. A value of 0 means that no item is selected.

Example:

<menu x="10" y="40"  width="120" height="30" value="2">
    <!-- Your menu options go here -->
</menu>

The <option> element

In order for your drop-down menu to have options, it must contain <option> elements.

Attributes:

Attribute Required Description
name (required) The name of this element

That’s right. The <option> element has only one attribute. In order to have your <option> elements actually do something useful, you need to attach bindings to them. Here’s an example:

<menu x="10" y="40"  width="120" height="30" requireSelection="true" placeholderText="Choose..." value="2">
    <option name="Menu Option 1">
        <!-- Set the text of a label element -->
        <binding type="control" level="ui" position="2" parameter="TEXT" translation="fixed_value" translationValue="You chose the first option." />
        <!-- Turn on this group -->
        <binding type="general" level="group" position="0" parameter="ENABLED" translation="fixed_value" translationValue="true" />
        <!-- Turn off this group -->
        <binding type="general" level="group" position="1" parameter="ENABLED" translation="fixed_value" translationValue="false" />
    </option>
    <option name="Menu Option 2">
        <!-- Set the text of a label element -->
        <binding type="control" level="ui" position="2" parameter="TEXT" translation="fixed_value" translationValue="You chose the second option." />
        <!-- Turn off this group -->
        <binding type="general" level="group" position="0" parameter="ENABLED" translation="fixed_value" translationValue="false" />
        <!-- Turn on this group -->
        <binding type="general" level="group" position="1" parameter="ENABLED" translation="fixed_value" translationValue="true" />
    </option>
  </menu>

As you can see, this example uses a menu to switch between two groups. It also sets the text of a text label. You’ll note the liberal use of the new fixed_value translation mode above. This means that when any of these options are selected, a fixed predetermined value is used for the value of that binding.

The <keyboard> element

The <keyboard> element lives underneath the <ui> element. This is where you specify settings relating to the on-screen keyboard. There should be only one <keyboard> element in your preset file. At this point, the only settings are color ranges which are specified using <color> sub-elements.

The <color> element

You can use <color> elements to change the color of portions of the on-screen keyboard. You can have as many <color> elements as you like. Only white keys are affected. It’s worth noting that colors specified in the <color> elements are overlayed on top of the white keys using a 75% transparency, so choose your colors accordingly. This is done to preserve the readability of the key labels.

<DecentSampler>
    <ui>
        <!-- Other stuff here -->
        <keyboard>
            <color loNote="36" hiNote="50" color="FF2C365E" />
            <color loNote="51" hiNote="57" color="FF6D9DC5" />
            <color loNote="58" hiNote="67" color="FFCCF3F5" />
            <color loNote="68" hiNote="73" color="FFE8DA9B" />
            <color loNote="74" hiNote="84" color="FFD19D61" />
        </keyboard>
    </ui>
    <!-- Other stuff here -->
</DecentSampler>
Attribute Description
loNote (required) The bottom of the range for which this color should be displayed. Format: MIDI Note number.
hiNote (required) The top of the range for which this color should be displayed. Format: MIDI Note number.
color (required) A text representation of the color to be used for this key range. See Appendix A for an explanation on these hex values.

The <groups> element (required)

Every dspreset file should have one and only one <groups> element. This is where you specify the samples that make up your sample library. This element lives right underneath the top-level <DecentSampler> element. The basic structure is this:

<DecentSampler>
    <groups>
        <group>
            <sample /> <!-- This is where -->
            <sample /> <!-- the samples   -->
            <sample /> <!-- get defined   -->
        </group>
    </groups>
</DecentSampler>
Attribute Description
volume (optional) The volume of the instrument as a whole. This will be reflected in the UI in the top-right corner. Value can be in linear 0.0-1.0 or in decibels. If it’s in decibels you must append dB after the value (example: “3dB”). Default: 1.0 (no volume change)
globalTuning (optional) Global pitch adjustment for changing note pitch. In semitones. For example 1.0 would be a half-step up. Default: 0
glideTime (optional) The glide/portamento time in seconds. A value of 0.0 would mean no portamento. This value can also be set at the <group> and <sample> levels, although most people will want to set it globally at the <groups> level. Default: 0.0
glideMode (optional) Controls the glide/portamento behavior. Possible values are: always (glide is always performed), legato (glide is performed only when transitioning from one note to another), and off. This value can also be set at the <group> and <sample> levels, although most people will want to set it globally at the <groups> level. Default: legato

The <group> element

Samples live in groups. There can be many group elements under the <groups> element. It can be useful to sort your samples into groups in order to apply similar settings to them or to control them with a knob. The order of groups in a file matters insofar as bindings will often reference groups by using an index. The first group in a file is group 0, the second is group 1, etc.

Attribute Description
enabled Whether or not this group is enabled. Possible values: true, false. Default: true (optional)
volume The volume of the group. Value can be in linear 0.0-1.0 or in decibels. If it’s in decibels you must append dB after the value (example: “3dB”). Default: 1.0 (optional)
ampVelTrack The degree to which the velocity of the incoming notes affects the volume of the samples in this group. 0 = not at all. 1 = volume is completely determined by incoming velocity. When the value is 1, a velocity of 127 (max velocity) yields a gain 1.0 (full volume), a velocity of 63 (half velocity) yields a gain of 0.5 (half volume), etc. (optional)
groupTuning Group-level pitch adjustment for changing note pitch. In semitones. For example 1.0 would be a half-step up and -1 would a half-step down. Default: 0 (optional)
The <sample> element

Underneath the <group> elements are <sample> elements. Each sample corresponds to a playable “zone” of your instrument. Attributes:

Attribute Description
path (required) The relative path of the sample file to play for this zone.
rootNote (required) The MIDI note number (from 1 to 127) of the note.
loNote (optional) The MIDI note number (from 1 to 127) of the lowest note for which the zone should be triggered. Default: 0.
hiNote (optional) The MIDI note number (from 1 to 127) of the highest note for which the zone should be triggered. Default: 127.
loVel (optional) The lowest velocity for which this zone should be triggered. Default: 0
hiVel (optional) The highest velocity for which this zone should be triggered. Default: 127
loCCN hiCCN (optional) Using these parameter, you can use MIDI continuous controllers to filter whether or not a note should be played. This lets you, for example, have one set of samples that get played when the piano sustain pedal is down and another set that get played when it is up. Each time a MIDI CC value comes for a specific CC#, the engine stores that value. When a “note on” signal is received, the engine makes a decision (based on the last received value and the range defined by these attributes) about whether or not this sample should be played. If you use loCCN, you must also use a corresponding hiCCN for the same MIDI CC number so that you are defining a range of values. Example: loCC64="90" and hiCC64="127" would mean that a “note on” message will only trigger this sample if the last received value for CC64 (Sustain Pedal) is between 90 and 127. This can also be set at the <group> level. Default:-1 (off)
start (optional) The frame/sample position of the start of the sample audio. This is useful if the sample starts midway through the audio file. Default: 0
end (optional) The frame/sample position of the end of the sample audio. The is useful is the zone ends before the end of the audio file. Default: the file’s length in samples minus 1.
tuning (optional) A fine-tuning number (in semitones) for changing the note pitch. e.g 1.0 would be a half-step up. Default: 0
volume (optional) The volume of the sample. Value can be in linear 0.0-1.0 or in decibels. If it’s in decibels you must append dB after the value (example: “3dB”). Default: 1.0
pan (optional) A number of -100 to 100. -100 in panned all the way to the left, 100 is panned all the way to the right. This can also be set at the <group> or <groups> levels. Default: 0
pitchKeyTrack (optional) A number from 0.0 to 1.0. 0 means that the pitch will stay the same regardless of what note is played. 1 means that the pitch will increase by one semitone when the note increases by one semitone (i.e. normal key pitch tracking). This can also be set at the <group> level. Default: 1
trigger (optional) Valid values: attack means a sample is played when the note on message is received. release means the sample is played when the note off message is received (aka a release trigger). first means that the sample will only be played if no other notes are playing. legato means that the sample will only be played if some other notes are already playing. This can also be set at the <group> level. Default: attack.
tags (optional) A command-separated list of tags. Example: tags=”rt,mic1”. These are useful when controlling volumes using tags. See Appendix D.
onLoCCN onHiCCN (optional) If you want a sample to be triggered when a MIDI CC controller message comes in, for example for piano pedal down and pedal up samples, you use these attributes to specify the range of values that should trigger the sample. If you use onLoCCN, you must also use a corresponding onHiCCN for the same MIDI CC number. Example: onLoCC64="90" and onHiCC64="127" would mean that values of CC64 (Sustain Pedal) between 90 and 127 will trigger the given sample. This can also be set at the <group> level. Default:-1 (off)

Looping

Attribute Description
loopStart (optional) The frame/sample position of the start of the sample’s loop. If this is not specified, but the sample is a wave file with embedded loop markers, those will be used instead. Default: 0
loopEnd (optional) The frame/sample position of the end of the sample’s loop. If this is not specified, but the sample is a wave file with embedded loop markers, those will be used instead. Default: the file’s length in samples minus 1.
loopCrossfade (optional) When loop crossfades are used, instead of simply looping at a specific end point, a portion of the audio from before the loop point is faded in just as the audio from the end of the loop is faded out. In this way, smooth audio loops can be achieved on samples that weren’t specifically prepared as looping. This parameter is used for specifying the length of the crossade region in frames/samples. This can also be set at the <group> level. Default: 0 (crossfades off).
loopCrossfadeMode (optional) This parameter is used to specify the curve used for crossfading when loop crossfades are turned on. This can also be set at the <group> level. Value values: linear, equal_power. Default: equal_power.
loopEnabled (optional) A boolean value indicating whether or not the loop should be used. Valid values: true, false

Amplitude Envelope

Each sample has its own ADSR amplitude envelope.

Attribute Description
attack (optional) The attack time in seconds of the amplitude envelope of this zone. This can also be set at the <group> or <groups> levels.
decay (optional) The decay time in seconds of the amplitude envelope of this zone. This can also be set at the <group> or <groups> levels.
sustain (optional) The sustain level (0.0 - 1.0) of the amplitude envelope of this zone. This can also be set at the <group> or <groups> levels.
release (optional) The release time in seconds of the amplitude envelope of this zone. This can also be set at the <group> or <groups> levels.

The curve shapes of the attack, decay, and release zones can be changed as well. All three of the of the following parameters use the same system: a value from -100 to 100 that determines the shape of the curve. -100 is a logarithmic curve, 0 is a linear curve, and 100 is an exponential curve.

-100 is a logarithmic curve, 0 is a linear curve, and 100 is an exponential curve

Attribute Description Default Value
attackCurve (optional) A value from -100 to 100 that determines the shape of the attack curve. This can also be set at the <group> or <groups> levels. -100 (logarithmic)
decayCurve (optional) A value from -100 to 100 that determines the shape of the decay curve. The decay time in seconds of the amplitude envelope of this zone. This can also be set at the <group> or <groups> levels. 100 (exponential)
releaseCurve (optional) A value from -100 to 100 that determines the shape of the release curves. The release time in seconds of the amplitude envelope of this zone. This can also be set at the <group> or <groups> levels. 100 (exponential)

Round Robins

Round robins allow different samples to be played each time a zone is triggered. This is especially useful with sounds that have short attacks (such as drums), and is a great way to keep your sample libraries from sounding fake. In order for round robins to work, you must specify both a seqMode and a seqPosition for all samples. If you have several different sets of round robins with different lengths, you’ll want to set the seqLength value as well. There are several round-robin modes:

Attribute Description
seqMode (optional) Valid values are random, true_random, round_robin, and always. A value indicating the desired round robin behavior for this sample or group of samples. This can also be set at the <group> and <groups> levels. Default: always
seqLength (optional) The length of the round robin queue. This can also be set at the <group> or <groups> levels. If this is left out, then the engine will try to auto-detect the length of the roudn robin sequence. Default: 0
seqPosition (optional) A number indicating this zone’s position in the round robin queue. This can also be set at the <group> level. Default: 1

Voice-Muting / Legato

Looping

Attribute Description
silencedByTags (optional) A command-separated list of tags. Example: tags=”rt,mic1”. If a sample containing one of these tags gets triggered, then this sample will be stopped. This is useful when setting up drums as it will allow you mute one hi-hat when another hi-hat plays. See Appendix D.
silencingMode (optional) Controls how quickly voices get silenced. fast = immediately; normal = triggers the sample’s release phase. This second option, when used in conjunction with the release attribute, allows you to specify a longer release time. Values: fast, normal. Default: fast
previousNotes (optional) Only play this sample if the previously triggered note equals one of these notes. Format: a comma-separated list of MIDI note numbers (from 1 to 127) of the note.
legatoInterval (optional) This is similar to the previousNote attribute. This causes the engine to only play the sample if the previously triggered note is exactly this semitone distance from the previous note. For example, if the note for which this sample is being triggered is a C3 and the legatoInterval is set to -2, then the sample will only play if the previous note was a D3 because D3 minus 2 semitones equals C3. Format: This can be a positive or negative whole number.

The <effects> element

Adding global, instrument-wide effects is easy: just add an <effects> element right below your top-level <DecentSampler> element.

It is also possible to have effects that only get added to a specific group. To adding effects that only apply to a specific group, all you need to do is create an <effects> group that lives underneath the <group> element for the group you want to affect.

Group level effects are initialized every time a note is started and destroyed every time a note is stopped. If you play two notes simultaneously, two instances of this effect will be created and these will be independent of eachother. As a result, they use more CPU than global effects.

NOTE: Only certain effects will work as group-level effects: lowpass filter, hipass filter, bandpass filter, gain, and chorus. Delay and reverb cannot work properly as they will be deleted before their tail peters out.

The <effect> element

Within the <effects> element, you can have any number of <effect> sub-elements. These specify parameters for each individual effect that you would like to have in your global effects chain. There are currently only a handful effects available although more could definitely be added on request:

Low-pass, Band pass, and Hi-pass filter

A 2-pole resonance filter that can be either a lowpass, bandpass, or highpass filter

Example:

<DecentSampler>
  <effects>
    <effect type="lowpass_4pl" resonance="0.7" frequency="22000" />
  </effects>
</DecentSampler>

Attributes:

Attribute Type Valid Range Default
type Required The type of filter Must be either lowpass (legacy: lowpass_4pl), bandpass, or highpass
resonance Optional The filter resonance (Q) 0 - 1.0, where 1.0 is big, 0 is small. 0.7
frequency Optional The filter frequency 0 - 1.0, where 0 is not damped, 1.0 is fully damped. 0.3
Gain effect

Applies a volume boost or cut to the output signal.

Example:

<DecentSampler>
  <effects>
    <effect type="gain" level="0.5" />
  </effects>
</DecentSampler>

Attributes:

Attribute Type Default Valid Range
type Required Must be gain gain
level Required The amount of gain to be applied expressed as a linear number. In other words, gain of 0.5 reduces sound by 50% (this is equivalent to -6dB). A value of 2.0 doubles the volume of the sound (equivalent to +6dB) 0.7 0 - 8.0, where 1.0 is no change.
Reverb effect

Example:

<DecentSampler>
  <effects>
    <effect type="reverb" roomSize="" damping="" wetLevel="" />
  </effects>
</DecentSampler>

Attributes:

Attribute Type Valid Range Default
type Required Must be reverb reverb
roomSize Optional The reverb “room size” 0 - 1.0, where 1.0 is big, 0 is small. 0.7
damping Optional The reverb damping level 0 - 1.0, where 0 is not damped, 1.0 is fully damped. 0.3
wetLevel Optional The volume of reverb signal 0 - 1.0 0
Delay effect

Example:

<DecentSampler>
  <effects>
    <effect type="delay" delayTime="0.5" stereoOffset="0.01" feedback="0.2" wetLevel="0.5" />
  </effects>
</DecentSampler>

Attributes:

Attribute Type Valid Range Default
type Required Must be reverb reverb
delayTime Optional The delay time in seconds 0 - 10.0 0.7
feedback Optional The feedback level. 0 - 1.0, where 0 is no feedback, 1.0 is max feedback. 0.2
stereoOffset Optional The parameter allows you to introduce delay variations between the left and right channels. Half of this amount is subtracted from the left channel’s delay time and half of this amount is added to the right channel’s delay time. For example, if the delayTime is 0.5 seconds and the stereoOffset is 0.02 s, then the actual left channel delay time will be 0.49 s and the actual right channel delay time will be 0.51 s so that the two channels are offset by 0.02 seconds. -10 - 10 0
wetLevel Optional The volume of the delay signal 0 - 1.0 0.5
Chorus effect

Example:

<DecentSampler>
  <effects>
    <effect type="chorus" mix="0.5" modDepth="0.2" modRate="0.2"/>
  </effects>
</DecentSampler>

Attributes:

Attribute Type Valid Range Default
type Required Must be chorus chorus
mix Optional The wet/dry mix which controls how much of the chorus signal we hear 0 - 1.0, where 1.0 is just chorus, 0 is just dry signal. 0.5
modDepth Optional The modulation depth of the effect 0 - 1.0, where 0 is no modulation, 1.0 is max modulation. 0.2
modRate Optional The modulation speed in Hz. 0 - 10.0 0.2
Phaser effect

Example:

<DecentSampler>
  <effects>
    <effect type="phaser" mix="0.5" modDepth="0.2" modRate="0.2" centerFrequency="400" feedback="0.7" />
  </effects>
</DecentSampler>

Attributes:

Attribute Type Valid Range Default
type Required Must be phaser phaser
mix Optional The wet/dry mix which controls how much of the chorus signal we hear 0 - 1.0, where 1.0 is just chorus, 0 is just dry signal. 0.5
modDepth Optional The modulation depth of the effect 0 - 1.0, where 0 is no modulation, 1.0 is max modulation. 0.2
modRate Optional The modulation speed in Hz. 0 - 10.0 0.2
centerFrequency Optional The center frequency (in Hz) of the phaser all-pass filters modulation 0 - 1.0 400
feedback Optional Sets the feedback volume of the phaser. -1 - 1.0 0.7

The <midi> element

MIDI mappings can be added to your instrument by adding a <midi> element right below your top-level <DecentSampler> element.

The <cc> element

Within the <midi> element, you can have any number of <cc> elements. These allow you to map changes in incoming continuous controller messages to specific parameters of your instrument. To use this functionality, you’ll want to add a separate <cc> element for each CC number you would like to respond to. The <cc> element has a single required attribute number="" which specifies the number (from 0 to 127) of the continuous controller you would like to listen on. Beneath the <cc> element, you can have any number of bindings.

<midi>
  <cc number="11">
    <binding level="ui" type="control" position="0" parameter="VALUE" translation="linear" 
             translationOutputMin="0" translationOutputMax="1"/>
  </cc>
  <cc number="1">
    <binding level="ui" type="control" position="1" parameter="VALUE" translation="linear" 
             translationOutputMin="0" translationOutputMax="1"/>
  </cc>
</midi>

The <note> element

Within the <midi> element, you can have any number of <note> elements. These allow you to map specific notes to specific parameters of your instrument. To use this functionality, you’ll want to add a separate <note> element for each MIDI note you would like to respond to. The <note> element has a single required attribute note="" which specifies the number (from 0 to 127) of the MIDI note you would like to listen on. Beneath the <note> element, you can have any number of bindings. Here is an example of how keyswitches could be set up:

<midi>
  <note note="11">
    <binding type="general" level="group" position="0" parameter="ENABLED" translation="fixed_value" translationValue="true" />
    <binding type="general" level="group" position="1" parameter="ENABLED" translation="fixed_value" translationValue="false" />
  </note>
  <note note="12">
    <binding type="general" level="group" position="0" parameter="ENABLED" translation="fixed_value" translationValue="false" />
    <binding type="general" level="group" position="1" parameter="ENABLED" translation="fixed_value" translationValue="true" />
  </note>
</midi>

In the above keyswitch example, MIDI note 11 turns on group 0 and turns off group 1, whereas MIDI note 12 does the opposite. Note the use of the fixed_value translation type.

Bindings within the <midi> section

The bindings that the <cc> and <note> element listens on are the same as those used by the UI controls. See Appendix B for a complete description of these.

If you have a UI control mapped to the same internal parameter as a MIDI mapping, you’ll want to have your MIDI mapping control the UI control instead of the parameter directly. The benefit of doing this is that, as the MIDI CC input is received, the UI control will be updated as well as the desired internal parameter.

The way to accomplish this is to make use of the labeled_knob or control binding types (control was introduced in version 1.1.7) as follows:

<binding level="ui" type="control" position="0" parameter="VALUE" translation="linear" translationOutputMin="0" translationOutputMax="1"/>

You’ll notice that the control type has a level value of ui and a parameter value of VALUE. Another thing to notice is the position="" parameter. This contains the 0-based index of the control to be modified. NOTE: The indexes of the parameter list includes all UI controls, including <label> and menu controls, so you’ll want to account for that when calculating your positions.

An example of changing a menu option based on a MIDI note (keyswitch) would look like this:

<midi>
  <note note="11">
    <binding type="control" level="ui" position="1" parameter="VALUE" translation="fixed_value" translationValue="1" />
  </note>
  <note note="12">
    <binding type="control" level="ui" position="1" parameter="VALUE" translation="fixed_value" translationValue="2" />
  </note>
</midi>

The <modulators> element

Version 1.6.0 of Decent Sampler officially introduces the new <modulators> section into the .dspreset format. This section lives below the top-level <DecentSampler> element and it is where all modulators for the entire sample library live.

<DecentSampler>
    <modulators>
        <!-- Your modulators go here. -->
    </modulators>
</DecentSampler>

The <lfo> element

Underneath the <modulators> section, you can have any number of different LFOs, which are defined using an <lfo> element, for example:

<modulators>1
  <lfo shape="sine" frequency="2" modAmount="1.0"></lfo>
</modulators>

This element has the following attributes:

The <envelope> element

In addition to LFOs, you can also have additional ADSR envelopes. These can be useful for controlling group-level effects, such as low-pass filters. If this is what you wish to achieve, make sure you check out the section on group-level effects below.

To create an envelope, use an <envelope> element:

This element has the following attributes: - attack: The length in seconds of the attack portion of the ADSR envelope - decay: The length in seconds of the decay portion of the ADSR envelope - sustain: The height of the sustain portion of the ADSR envelope. This is expressed as a value between 0 and 1. - release: The length in seconds of the release portion of the ADSR envelope - modAmount: This value between 0 and 1 controls how much the modulation affects the things it is targeting. In conventional terms, this is like the modulation depth. Default value: 1.0. - scope: Whether or not this LFO exists for all notes or whether each keypress gets its own LFO. Possible values are global and voice (default for envelopes). If voice is chosen, a new LFO is started each time a new note is pressed.

How to use <binding>s in conjunction with modulators

In order to actually have your LFOs and envelopes do anything, you need to have bindings under them. If you are not familiar with the concept of bindings, you may want to read this section then return here. Bindings tell the engine which parameters the LFO should be affecting and how. Here is an example:

<modulators>
    <lfo shape="sine" frequency="2" modAmount="1.0">
        <!-- This binding modifies the frequency of a low-pass filter  -->
        <binding type="effect" level="instrument" effectIndex="0" parameter="FX_FILTER_FREQUENCY" modBehavior="add" translation="linear" translationOutputMin="0" translationOutputMax="2000.0"  />
    </lfo>
</modulators>

There are a few differences between bindings as they are used by knobs and the ones used by modulators. Specifically, when you move a UI control that has a binding attached, the engine actually goes out and changes the value of the parameter that is targeted by that binding. For example, if you have a knob that controls a lowpass filter’s cutoff frequency, moving that knob will cause that actual frequency of that filter to change. In other words, the changes that the knob is making on the underlying sample library are permanent. The same is also true for bindings associated with MIDI continuous controllers.

Modulators, on the other hand, do not work this way. If a modulator (such as an LFO) changes its value, the engine looks at the bindings associated with that LFO and then makes a list of temporary changes to the underlying data. When it comes time to render out the effect, it consults both the permanent value and the temporary modulation values. As a result of this difference in the way bindings are handled, only some parameters are “modulatable.” At time of press, the following parameters are modulatable:

Modulator scope: global or voice-level

By default, all modulators will be created at the global level. This means that there will be exactly one modulator that is shared by all voices. In many situations, such as an LFO modulating a single low-pass filter which is shared by all of voices, this is often what we want.

But there are other situations where we don’t want our modulator to be global. In such cases we

<modulators>
    <envelope attack="2" decay="0" sustain="1" release="0.5" modAmount="1.0">
        <binding type="effect" level="group" groupIndex="0" effectIndex="0" parameter="FX_FILTER_FREQUENCY" translation="linear" translationOutputMin="0" translationOutputMax="4000.0" modBehavior="add" />
    </envelope>
</modulators>

Note that this voice-level modulator is now targeting a group level effect.

The <tags> element

The <tags> element lives right below your top-level <DecentSampler> element. It allows you to specify details about the tags you use throughout your instrument. It is however not actually necessary to include a <tags> element for every tag you use. You only need to create this if you want to specify additional details about your tags.

The <tag> element

Underneath the <tags> element, you can have any number of <tag> elements. These specify details for each individual tag that you use throughout your sample mapping. Attributes:

Attribute Description
enabled (optional) A number for 0.0 to 1.0 that specifies the initial volume for a tag. Default: 1.0
volume (optional) A number for 0.0 to 1.0 that specifies the initial volume for a tag. Default: 1.0
polyphony (optional) A whole number that specifies the number of voices allowed for this tag.

Appendix A: The Color Format

Colors are represented throughout the dspreset files using an 8-digit ARGB color format. These are identical to web color hex codes except with an additional 2-digit hex number in front of them. The first two digits are a hexadecimal representation of alpha level with 00 being fully transparent, 80 being 50% transparent, and FF being fully opaque.

Examples:

Appendix B: The <binding> element

Adding a binding to a UI control, MIDI handler, or modulator tells the DecentSampler engine that it should take input from a source and use it to change values in another part of the engine. An example of this would be a knob which controls the volume of a group, a CC controller that changes an effect parameter, or an LFO that modulates an effect parameter.

In order to set up a binding for a specific source, create a <binding> element within the source element.

In this example, a labeled knob is controlling the volume of the first group of samples (group 0):

<DecentSampler>
  <ui>
    <tab>
      <labeled-knob x="420" y="100" label="RT" type="float" minValue="0" maxValue="1" value="0.3" textSize="20">
        <binding type="amp" level="group" position="0" parameter="AMP_VOLUME" translation="linear" translationOutputMin="0" translationOutputMax="1.0"  />
      </labeled-knob>
    </tab>
  </ui>
</DecentSampler>

Here’s a full list of parameters for the <binding> element:

Attribute Description
type This tells the engine what type of parameter this is. Valid values are: “amp”, “effect”, “control”. Required
level Valid values are ui, instrument, group Required
position The specific 0-based index of the element to be modified by this binding. If you are targeting a group, for example, the first group would be 0, the second group would be 1, etc. Required
controlIndex When a binding is targeting a control, this is the same thing as the position attribute. It is a specific 0-based index of the control to be modified by this binding. If you are targeting an group-level effect, this would specified the group under which the effect lives. Optional
groupIndex When a binding is targeting a group, this is the same thing as the position attribute. It is a specific 0-based index of the group to be modified by this binding. If you are targeting an group-level effect, this would specified the group under which the effect lives. Optional
effectIndex When a binding is targeting an effect, this is the same thing as the position attribute. It is a specific 0-based index of the effect to be modified by this binding. Optional
modulatorIndex When a binding is targeting a modulator, this is the same thing as the position attribute. It is a specific 0-based index of the modulator to be modified by this binding. Optional
tags A comma-separated list of tags to be modified by this binding. This allows you to set values for multiple groups at once by targeting a tag that is assigned to the groups. Optional
identifier A string identifying the specific parameter that you wish to change. If you are modulating based on tags, you would put the tag you are targeting here. See Appendix D for example. Required
parameter A token describing the specific kind of parameter that you wish to change. A list of controller parameters are below. Required
translation Valid values are fixed_value, linear and table. Explanation of both translation modes is in a separate section below. Default: linear Optional
translationOutputMin This is the min value this binding should send to the target parameter. This is only looked at if translation is set to linear. Optional
translationOutputMax This is the max value this binding should send to the target parameter. This is only looked at if translation is set to linear. Optional
translationReversed Valid values are true and false. Default: false. This is only looked at if translation is set to linear. Optional
translationTable A list of input-output pairs that make up the translation table. The input and output are separated by commas. The groups of coordinates themselves are separated by semi-colons. Default: 0,0;1,1. You must have at least two coordinates in your list. This is only looked at if translation is set to table. Optional
translationValue The value that should be passed along when translation is set to fixed_value. Optional

Controllable Parameters

This is a list of parameters that can be used in conjunction with the <binding> element above.

Description type level parameter Additional required parameters Valid Range Modulatable
Global Volume amp instrument AMP_VOLUME N/A 0.0 - 16.0
Global Tuning amp instrument GLOBAL_TUNING N/A -36.0 - 36.0
Global Pan amp instrument PAN N/A -100 - 100
Amplitude Velocity Tracking amp instrument AMP_VEL_TRACK N/A 0.0 - 1.0
Global Amp Envelope Attack amp instrument ENV_ATTACK N/A 0.0 - 10.0
Global Amp Envelope Attack Curve Shape amp instrument ENV_ATTACK_CURVE N/A -100 - 100
Global Amp Envelope Decay amp instrument ENV_DECAY N/A 0.0 - 25.0
Global Amp Envelope Decay Curve Shape amp instrument ENV_DECAY_CURVE N/A -100 - 100
Global Amp Envelope Sustain amp instrument ENV_SUSTAIN N/A 0.0 - 1.0
Global Amp Envelope Release amp instrument ENV_RELEASE N/A 0.0 - 25.0
Global Amp Envelope Release Curve Shape amp instrument ENV_RELEASE_CURVE N/A -100 - 100
Glide/Portamento Time amp instrument GLIDE_TIME N/A 0.0 - 10.0
Lowpass Filter Cutoff effect instrument FX_FILTER_FREQUENCY N/A 0.0 - 22000.0 Yes
Lowpass Filter Resonance effect instrument FX_FILTER_RESONANCE N/A 0.0 - 2.0 Yes
Reverb Wet Level effect instrument FX_REVERB_WET_LEVEL N/A 0.0 - 1.0 Yes
Reverb Room Size effect instrument FX_REVERB_ROOM_SIZE N/A 0.0 - 1.0 Yes
Reverb Damping effect instrument FX_REVERB_DAMPING N/A 0.0 - 1.0 Yes
Chorus/Phaser Mix Level effect instrument FX_MIX N/A 0.0 - 1.0 Yes
Chorus/Phaser Mod Depth effect instrument FX_MOD_DEPTH N/A 0.0 - 1.0 Yes
Chorus/Phaser Mod Rate effect instrument FX_MOD_RATE N/A 0.0 - 10.0 Yes
Phaser Center Frequency effect instrument FX_CENTER_FREQUENCY N/A 0.0 - 22000.0 Yes
Phaser/Delay Feedback effect instrument FX_FEEDBACK N/A 0.0 - 1.0 Yes
Delay Time effect instrument FX_DELAY_TIME N/A 0.0 - 1.0 Yes
Delay Stereo Offset effect instrument FX_STEREO_OFFSET N/A 0.0 - 1.0 Yes
Delay Wet Level effect instrument FX_WET_LEVEL N/A 0.0 - 1.0 Yes
Gain Level effect instrument LEVEL N/A 0.0 - 8.0 Yes
Group Enabled / Disabled amp group ENABLED groupIndex or position contains the 0-based index of the group true, false
Group Volume amp group AMP_VOLUME groupIndex or position contains the 0-based index of the group 0.0 - 16.0 Yes
Group Tuning amp group GROUP_TUNING groupIndex or position contains the 0-based index of the group -36.0 - 36.0 Yes
Pan amp group PAN groupIndex or position contains the 0-based index of the group -100 - 100 Yes
Amplitude Velocity Tracking amp group AMP_VEL_TRACK groupIndex or position contains the 0-based index of the group 0.0 - 1.0
Group Amp Envelope Attack amp group ENV_ATTACK groupIndex or position contains the 0-based index of the group 0.0 - 10.0
Group Amp Envelope Decay amp group ENV_DECAY groupIndex or position contains the 0-based index of the group 0.0 - 25.0
Group Amp Envelope Sustain amp group ENV_SUSTAIN groupIndex or position contains the 0-based index of the group 0.0 - 1.0
Group Amp Envelope Release amp group ENV_RELEASE groupIndex or position contains the 0-based index of the group 0.0 - 25.0
Group Glide/Portamento Time amp group GLIDE_TIME groupIndex or position contains the 0-based index of the group 0.0 - 10.0
Tag Enabled amp tag TAG_ENABLED identifier contains the tag name true, false
Tag Volume amp tag TAG_VOLUME identifier contains the tag name 0.0 - 16.0
UI Control Value control ui VALUE controlIndex or position contains the 0-based index of the control in question (see note 1 below) 0.0 - 1.0
UI Control Text control ui TEXT controlIndex or position contains the 0-based index of the control in question (see note 1 below) Text
UI Image Control Path control ui PATH controlIndex or position contains the 0-based index of the control in question (see note 1 below) Text
Modulator Amount (Depth) modulator instrument MOD_AMOUNT modulatorIndex contains the 0-based index of the modulator in question 0.0 - 1.0
LFO Modulator Rate (or Frequency) modulator instrument FREQUENCY modulatorIndex contains the 0-based index of the modulator in question 0.0 - 22000.0
Envelope Modulator Attack modulator instrument ENV_ATTACK modulatorIndex contains the 0-based index of the modulator in question 0.0 - 10.0
Envelope Modulator Attack Curve Shape modulator instrument ENV_ATTACK_CURVE modulatorIndex contains the 0-based index of the modulator in question -100 - 100
Envelope Modulator Decay modulator instrument ENV_DECAY modulatorIndex contains the 0-based index of the modulator in question 0.0 - 25.0
Envelope Modulator Decay Curve Shape modulator instrument ENV_DECAY_CURVE modulatorIndex contains the 0-based index of the modulator in question -100 - 100
Envelope Modulator Sustain modulator instrument ENV_SUSTAIN modulatorIndex contains the 0-based index of the modulator in question 0.0 - 1.0
Envelope Modulator Release modulator instrument ENV_RELEASE modulatorIndex contains the 0-based index of the modulator in question 0.0 - 25.0
Envelope Modulator Release Curve Shape modulator instrument ENV_RELEASE_CURVE modulatorIndex contains the 0-based index of the modulator in question -100 - 100
  1. NOTE: The indexes of the parameter list also include UI controls that are not editable, such as <label> UI controls, so you’ll want to account for that when calculating your positions.

    Here’s a quick example:

    If your UI’s <tab> section has the following elements under it: <label>, <control>,<label>,<control>. The position indexes of the four elements will be 0, 1, 2, 3. Therefore, the indexes of the two <control> elements will be 1 and 3, respectively.

Translation Modes

There are currently three binding translation modes: linear, table, fixed_value

Mode #1: linear

linear mode allows values that come in to be scaled up or down before they get passed along to the binding’s target. If you set your translation mode to linear you should also translationOutputMin and translationOutputMax.

Example usage:

<binding level="ui" type="control" position="0" parameter="value" translation="linear" 
               translationOutputMin="0" translationOutputMax="1"/>

Mode #2: table

table mode allows you to transform the binding’s input in a more complex fashion before it gets passed along to the binding’s target. If you set your translation mode to table you must define the translationTable parameter as well. This consists of a series of input-output pairs, separated by semi-colons.

Mode #3: fixed_value

fixed_value mode allows you to completely disregard the input of a binding and instead always use a supplied value. In order to use this translation mode, you must also specify a translationValue. This can be very useful when trying to have menu options enable and disable groups. An example usage:

<binding type="general" level="group" position="1" parameter="ENABLED" translation="fixed_value" translationValue="true" />

Appendix C: Boilerplate .dspreset File

<?xml version="1.0" encoding="UTF-8"?>
<DecentSampler minVersion="1.0.0">
  <ui width="812" height="375" layoutMode="relative"
      bgMode="top_left">
    <tab name="main">
      <labeled-knob x="445" y="75" width="90" textSize="16" textColor="AA000000" 
                    trackForegroundColor="CC000000" trackBackgroundColor="66999999" 
                    label="Attack" type="float" minValue="0.0" maxValue="4.0" value="0.01" >
        <binding type="amp" level="instrument" position="0" parameter="ENV_ATTACK" />
      </labeled-knob>
      <labeled-knob x="515" y="75" width="90" textSize="16" textColor="AA000000" 
                    trackForegroundColor="CC000000" trackBackgroundColor="66999999" 
                    label="Release" type="float" minValue="0.0" maxValue="20.0" value="1" >
        <binding type="amp" level="instrument" position="0" parameter="ENV_RELEASE" />
      </labeled-knob>
      <labeled-knob x="585" y="75" width="90" textSize="16" textColor="AA000000" 
                    trackForegroundColor="CC000000" trackBackgroundColor="66999999" 
                    label="Chorus" type="float" minValue="0.0" maxValue="1" value="0" >
        <binding type="effect" level="instrument" position="1" parameter="FX_MIX" />
      </labeled-knob>
      <labeled-knob x="655" y="75" width="90" textSize="16" textColor="FF000000"
                    trackForegroundColor="CC000000" trackBackgroundColor="66999999"
                    label="Tone" type="float" minValue="0" maxValue="1" value="1">
        <binding type="effect" level="instrument" position="0" parameter="FX_FILTER_FREQUENCY"
                 translation="table" 
                 translationTable="0,33;0.3,150;0.4,450;0.5,1100;0.7,4100;0.9,11000;1.0001,22000"/>
      </labeled-knob>
      <labeled-knob x="725" y="75" width="90" textSize="16" textColor="AA000000" 
                    trackForegroundColor="CC000000" trackBackgroundColor="66999999" 
                    label="Reverb" type="percent" minValue="0" maxValue="100" 
                    textColor="FF000000" value="50">
        <binding type="effect" level="instrument" position="2" 
                 parameter="FX_REVERB_WET_LEVEL" translation="linear" 
                 translationOutputMin="0" translationOutputMax="1" />
      </labeled-knob>
    </tab>
  </ui>
  <groups attack="0.000" decay="25" sustain="1.0" release="0.430" volume="-3dB">
    <group>
      <sample loNote="21" hiNote="21" rootNote="21" path="DefaultPiano-21.aif"
              length="805888"/>
      <sample loNote="22" hiNote="33" rootNote="33" path="DefaultPiano-33.aif"
              length="807552"/>
      <sample loNote="34" hiNote="45" rootNote="45" path="DefaultPiano-45.aif"
              length="759168"/>
      <sample loNote="46" hiNote="57" rootNote="57" path="DefaultPiano-57.aif"
              length="756480"/>
      <sample loNote="58" hiNote="69" rootNote="69" path="DefaultPiano-69.aif"
              length="758656"/>
      <sample loNote="70" hiNote="77" rootNote="77" path="DefaultPiano-77.aif"
              length="595328"/>
      <sample loNote="78" hiNote="89" rootNote="89" path="DefaultPiano-89.aif"
              length="457600"/>
      <sample loNote="90" hiNote="96" rootNote="96" path="DefaultPiano-96.aif"
              length="469888"/>
      <sample loNote="94" hiNote="108" rootNote="108" path="DefaultPiano-108.aif"
              length="75264"/>
    </group>
  </groups>
  <effects>
    <effect type="lowpass" frequency="22000.0"/>
    <effect type="chorus"  mix="0.0" modDepth="0.2" modRate="0.2" />
    <effect type="reverb" wetLevel="0.5"/>
  </effects>
  <midi>
    <!-- This causes MIDI CC 1 to control the 4th knob (cutoff) -->
    <cc number="1">
      <binding level="ui" type="control" parameter="VALUE" position="3" 
               translation="linear" translationOutputMin="0" 
               translationOutputMax="1" />
    </cc>
  </midi>
</DecentSampler>

Appendix D: How to Control Parameters Using Tags (Example: Mic-level Knobs)

As of version 1.0.2, the best way to implement mic-level knobs is using the new sample tagging feature. It is possible to assign tags to specific samples. In this way, you can specify which type of sound they are:

<sample volume="0.0dB" tags="note,mic1" />
<sample volume="0.0dB" tags="rt,mic1" />
<sample volume="0.0dB" tags="note,mic2" />
<sample volume="0.0dB" tags="rt,mic2" />

You can also assign tags at the group level. You can also mix and match, and the tags specified at the group level will be added to the list of tags already specified at the sample level:

<group tags="note">
  <sample volume="0.0dB" tags="mic1" />
  <sample volume="0.0dB" tags="mic2" />
</group>
<group tags="rt">
  <sample volume="0.0dB" tags="mic1" />
  <sample volume="0.0dB" tags="mic2" />
</group>

Then you can make controls with bindings that reference those tags:

<control x="246" y="115" parameterName="MIC 1" style="linear_bar_vertical" type="float" minValue="0" maxValue="100" value="60" width="20" height="70" trackForegroundColor="FFFFFFFF" trackBackgroundColor="FF888888">
    <binding type="amp" level="tag" identifier="mic1" parameter="AMP_VOLUME" />
</control>

<control x="346" y="115" parameterName="MIC 2" style="linear_bar_vertical" type="float" minValue="0" maxValue="100" value="60" width="20" height="70" trackForegroundColor="FFFFFFFF" trackBackgroundColor="FF888888">
    <binding type="amp" level="tag" identifier="mic2" parameter="AMP_VOLUME" />
</control>

Appendix E: How to do voice-muting for drums

Voice muting makes use of the tags functionality, these are text labels that you can use to identify samples or groups of samples. You start by adding tags to all of your groups (you can also add them to individual samples if you’d like). Next, you add a silencedByTags attribute to groups or sample elements that you want to be silenced by other samples. When a sample with a tag matching one of the tags in the silencedByTags is played, it will silence the current sample (or group).

Here’s an example:

<DecentSampler>
    <groups>
        <group tags="hihat" silencedByTags="hihat" silencingMode="fast">
            <!-- Your samples go here. -->
        </group>
    </groups>
</DecentSampler>

Note the use of the silencingMode attribute as well (a value of “fast” means we immediately silence, whereas “normal” means we trigger the ADSR release phase).

Appendix F: How to implement true legato

Let’s walk through how to build a basic true legato instrument. Legato instruments generally consist of either two or three groups:

  1. First, there’s the initial looping sustain sample that will get played when the note is first pressed down.
  2. Then there is the legato transition sample that will get played when a second note gets pressed
  3. (optional) Depending on the implementation, there may be a third looping sustain group that gets played after the legato transition sample plays. In such cases, this third group usually contains the same samples as were used in group 1.

Step 1: Voice muting

Before we get into legato, let’s talk about voice muting. This is the behavior wherein one set of samples causes another set of samples to stop playing. This can be desirable in situations such as legato instruments where two samples should not be sounding at the same time.

In Decent Sampler, voice-muting makes use of tags. These are text labels that you can use to identify samples or groups of samples. You can add a silencedByTags attribute to groups or sample elements. This consists of a comma-separated list of tags that specify which samples should silence the current samples. When a sample with a tag matching one of the tags in the silencedByTags is played, it will silence the current sample (or group). Here’s an example:

<DecentSampler>
    <groups>
        <group tags="sustain" silencedByTags="legato" silencingMode="normal" release="1.0">
            <!-- Your sustain samples go here. -->
        </group>
        <group tags="legato" silencedByTags="legato" silencingMode="normal" release="1.0">
            <!-- Your legato samples go here. -->
        </group>
    </groups>
</DecentSampler>

In the above scenario, if a legato sample is matched, any sample that might be playing from the “sustain” group will be stopped.

It’s also worth mention the silencingMode attribute as well (a value of fast means we immediately silence that sample, whereas normal means we trigger the ADSR release phase).

Step 2: Legato

In order to specify which samples should be triggered first, we use the trigger attribute. This can that can be added to the <group> or individual <sample> tags. The default value is attack, but there are two useful new values:

Here is an example of how this might look in cunjunction with our example from above:

<DecentSampler>
    <groups>
        <group trigger="first" tags="sustain" silencedByTags="legato" silencingMode="normal" release="1.0">
            <!-- Your sustain samples go here. -->
        </group>
        <group trigger="legato" tags="legato" silencedByTags="legato" silencingMode="normal" release="1.0">
            <!-- Your legato samples go here. -->
        </group>
    </groups>
</DecentSampler>

Step 3: Specifying previous notes

When creating a legato instrument, it is often essential to limit which legato transition gets played based on which note we are transition from. This can be achieved using either the previousNote or the legatoInterval attributes. The previousNote attribute causes the engine to only play this sample if the previously triggered note matches the specified note. Example usage:

<sample path="Samples/LV_Legato_F2_G2.wav" rootNote="G2" loNote="G2" hiNote="G2" previousNote="F2" start="43000" />
<sample path="Samples/LV_Legato_G2_A2.wav" rootNote="A2" loNote="A2" hiNote="A2" previousNote="G2" start="43000" />

The legatoInterval attribute causes the engine to only play the sample if distance between the current note and the previously triggered note is exactly this semitone distance. For example, if the note for which this sample is being triggered is a C3 and the legatoInterval is set to -2, then the sample will only play if the previous note was a D3 because D3 minus two semitones equals C3.

Step 4: Polyphony

In legato instruments, it is sometimes useful to limit polyphony for a specific sample or set of samples. This is achieve using tags. At the top-level of your file, you can specify a element as follows:

<DecentSampler>
    <groups>
        <group tags="some-tag" >
            <!-- ... -->
        </group>
    </groups>
    <tags>
        <tag name="some-tag" polyphony="1" />
    </tags>
</DecentSampler>

Putting it all together

Here is a full example of a legato instrument:

<?xml version="1.0" encoding="UTF-8"?>

<DecentSampler pluginVersion="1">
  <groups>
    <group tags="sustain" silencedByTags="legato" trigger="first"
           silencingMode="normal" release="0.3">
      <sample path="Samples/LV_Sustain_D3.wav" rootNote="D3" loNote="C3" hiNote="D3"/>
      <sample path="Samples/LV_Sustain_E3.wav" rootNote="E3" loNote="D#3" hiNote="E3"/>
      <!-- More samples go here -->
    </group>
    <group tags="legato" silencedByTags="legato" trigger="legato"
           silencingMode="normal" attack="0.1" decay="0.2" sustain="0" release="1">
              previousNote="C#3"/>
      <sample path="Samples/LV_Legato_D3_E3.wav" rootNote="E3" loNote="E3"
              hiNote="E3" start="43000" previousNote="D3"/>
      <sample path="Samples/LV_Legato_E3_F3.wav" rootNote="F3" loNote="F3"
              hiNote="F3" start="43000" previousNote="E3"/>
      <!-- More samples go here -->
    </group>
    <group tags="legato-tails" silencedByTags="legato-tails" trigger="legato"
           attack="0.3" silencingMode="normal" release="0.3" start="5000">
      <sample path="Samples/LV_Sustain_D3.wav" rootNote="D3" loNote="C3" hiNote="D3"/>
      <sample path="Samples/LV_Sustain_E3.wav" rootNote="E3" loNote="D#3" hiNote="E3"/>
      <!-- More samples go here -->
    </group>
  </groups>
</DecentSampler>

Appendix G: Useful Tutorials and Resources