Posted on Leave a comment

Sample Creators: How to Use Buses & Auxiliary Outputs

As of version 1.12.0, Decent Sampler has support for both audio buses and auxiliary outputs. Buses are a powerful feature that allow you to route audio to different auxiliary outputs and apply effects to the audio. This can be useful for creating complex audio routing setups and adding effects to groups of samples. This tutorial will show you how to use buses and auxiliary outputs in Decent Sampler.

Auxilary Outputs

By default, all audio in Decent Sampler is routed to the main audio output. However, you can also route audio to secondary auxiliary outputs. Auxiliary outputs are additional audio outputs that can be used to route audio to external effects processors or other audio devices within your DAW. Decent Sampler supports up to 16 auxiliary stereo outputs, which can be used to create complex audio routing setups.

There are two ways that you can route audio to auxiliary outputs in Decent Sampler:

  1. You can use the outputXTarget attributes in the <sample><group>, or <groups> elements to directly specify the audio output that the sample should be routed to. The available options are MAIN_OUTPUT (the main audio output, which is the default) and AUX_STEREO_OUTPUT_1 through AUX_STEREO_OUTPUT_16 (the auxiliary outputs).
  2. You can also route audio from the samples to user-defined buses, and then route audio from the buses to the auxiliary outputs. This allows you to apply effects to the audio before sending it to the auxiliary outputs. We’ll cover that more below in the Buses section.

Example 1: Routing audio to an auxiliary output

In this example, we will route audio from a sample to an auxiliary output. To do this, we will use the outputXTarget attributes in the <sample> element to specify the audio output that the sample should be routed to. Here is an example of how you can route audio to AUX_STEREO_OUTPUT_1:

<group output1Target="MAIN_OUTPUT" output1Volume="1.0" output2Target="AUX_STEREO_OUTPUT_1" output2Volume="0.5" />
    <!-- Samples go here -->
</group>

In this example, the audio from the samples in the <group> element will be routed to the main audio output with a volume of 1.0, as well as to auxiliary output 1 with a volume of 0.5.

Buses

As mentioned above, buses can be used to create a more complex mix of the samples in the sample library as well as route audio to various audio outputs. Sample library designers can specify up to 16 buses in the <buses> element using the <bus> tag. Each bus can have its own volume and audio output settings. For a full list of attributes that can be used in the <bus> element, see the Buses Element documentation.

Example 2: Applying effects to audio using buses

In this example, we will apply an effect to audio using a bus. To do this, we will define a bus with an effect applied to it, and then route audio from the samples to the bus. Here is an example of how you can apply a reverb effect to audio using a bus:

<buses>
    <bus busVolume="0.5" output1Target="MAIN_OUTPUT" output2Target="AUX_STEREO_OUTPUT_1" output1Volume="0.8" output2Volume="0.5">
        <effects>
            <effect type="Reverb" wetDryMix="0.5" roomSize="0.5" damping="0.5" />
        </effects>
    </bus>
</buses>
<group output1Target="MAIN_OUTPUT" output2Target="BUS_1" output2Volume="1.0">
    <!-- Samples go here -->
</group>

In this example, a bus is defined with a reverb effect applied to it. The audio from the samples in the <group> element will be routed to the main audio output with a volume of 1.0, as well as to the bus with the reverb effect applied to it.

Conclusion

Buses and auxiliary outputs are powerful features in Decent Sampler that allow you to create complex audio routing setups and apply effects to groups of samples. By using buses and auxiliary outputs, you can create more dynamic and interesting sample libraries that take full advantage of Decent Sampler’s capabilities. You can find working examples of both audio outputs and buses in the official Decent Sampler example repository (look in the Example 10 directory).

Have fun!

– Dave Hilowitz

Posted on Leave a comment

Saving User Presets in DecentSampler: A Quick Guide

As a DecentSampler user, you’ve likely spent time tweaking and perfecting your sound. But what if you want to save these settings for future use? Good news! DecentSampler allows you to save user presets for any library you’re currently using. Here’s how to do it:

Step 1: Convert Your Library Format

Before you can save user presets, you need to ensure your library is in the correct format. Specifically, if your library is in a .dslibrary format, you must first convert it to either a .dsbundle or a folder-based preset.

Method 1: Converting .dslibrary files using Decent Sampler

The easiest way to convert a .dslibrary file is by using the DecentSampler plug-in itself:

  1. Simply drag that .dslibrary file onto the DecentSampler plug-in window. 
  2. You will see a box that says Do you want to install this preset?, click Yes.
  3. DecentSampler will decompress the .dslibrary file and create a new .dsbundle directory wherever you keep your sample libraries. For a list of the default sample library locations, see here.

Method 2: Manually Method

If Method 1 doesn’t work for some reason, you can also convert the file yourself. At their core, .dslibrary files are just .zip files with a different extension. 

  1. Change the extension on the .dslibrary file to .zip.
  2. Decompress the .zip file and put it wherever you store your sample libraries. If you are on macOS or Windows, this will be as easy as simply double-clicking the .zip file.

Step 2: Set Up Your Sound

Now that your library is in the correct format, load it and adjust the parameters to your liking. This could include changes to the envelope, filter settings, effects, or any other adjustable parameters within the library.

Step 3: Access the FILE… Menu

Once you’re happy with your sound, look for the FILE… menu. This is typically located at the top of the DecentSampler interface.

Step 4: Choose “Developers Tools > Save Preset…”

In the preset menu, you should see an option to “Save Preset…”. Click on this option.

Step 5: Select Save Location and Name Your Preset

A dialog box will appear, prompting you to save your preset. It is important that you save the preset in the same location as the other presets for this library – DecentSampler will usually suggest the correct location as the default location. Choose a name that’s descriptive and easy to remember. For example, “Warm Pad with Long Release” or “Punchy Bass with Distortion”.

Step 6: Confirm and Save

Once you’ve named your preset, click “Save” or “OK” to confirm. Your preset is now saved and ready for future use!

Accessing Your Saved Presets

To use your saved preset in the future:

  1. Load the same library you used when creating the preset (remember, it must be the .dsbundle or folder-based version).
  2. A box will pop up showing you all of the presets that belong to that library. 
  3. Find and select your new saved preset.

Remember, user presets are specific to the library you’re using. A preset saved while using one library won’t be available when you’re working with a different library.

Happy sampling, and enjoy the convenience of your personalized DecentSampler presets!

Posted on Leave a comment

Sample Creators: Here’s how to use the new XY Pad UI control

Hello! Version 1.11.12 of Decent Sampler introduces a useful new UI control: an XY pad. Here’s an example that I’ve colored yellow:

A screenshot of an XY Pad

This control is similar to a knob or a slider except that it works in two dimensions. For sample library creators who have worked with knobs and sliders will find that setting up this new control is pretty similar to those controls. The main difference between an XY pad and a knob is that instead of having one set of bindings it has two: one for the X axis and one for the Y axis. The code for the example above is this:

<xyPad x="10" y="10" width="300" height="195" parameterName="Pad" xValue="0.5576778054237366" yValue="0.4821614623069763" bgColor="77FFCC00" markerFillColor="FFFFFFFF" outlineColor="77FFFFFFF">
        <x>
          <binding type="amp" level="group" groupIndex="0" parameter="AMP_VOLUME" translation="linear" translationOutputMin="0" translationOutputMax="1"/>
          <binding type="amp" level="group" groupIndex="1" parameter="AMP_VOLUME" translation="linear" translationOutputMin="1" translationOutputMax="0"/>
        </x>
        <y>
          <binding type="effect" level="instrument" effectIndex="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"/>
        </y>
      </xyPad>
Code language: HTML, XML (xml)

You’ll note that the current value on the X axis can be found in the xValue attribute, and the current value for the Y axis can be found in the yValue attribute. XY Pads are automatable using DAW automation.

To learn more about this control, see the updated documentation here. You can download this example here – you’ll find it in the example 9 directory.

Enjoy!

– Dave

Posted on Leave a comment

Q: Is it possible to extract the samples contained within Decent Sampler instruments?

Occasionally, users will reach out and ask me whether it’s possible to extract the samples contained in a Decent Sampler library. One common use-case for this is users who want to use the samples with a hardware sampler such as an MPC or an SP-404. Anyway, the answer to the question is that in some cases it’s possible and in others it is not.

Me: “Are you sure you really want to do this?”

Before we go into the details of when it’s possible, it’s worth mentioning that a Decent Sampler instrument is usually much more than just a collection of samples: a creator of a library will often have made use of creative layering techniques as well as onboard effects, both of which play a huge part in producing the distinctive sound of a library. This means that the only reliable way of getting the intended sound of a library is to actually use the output from DecentSampler as your sound. This doesn’t mean that you are out of luck if you want to use these sounds with a hardware sampler. You can always load DecentSampler up in your DAW of choice, play a bunch of long notes, and then export the audio out from that session. This will often yield better sound than if you were to just go directly into the sample library and grab the underlying samples.

You: “OK, but I still want to do it!”

So, assuming that you really do want to grab the underlying audio files, here’s what you need to know. First, if the sample library is a commercial release and copy-protected then you are out of luck: the underlying wave files will all encrypted and the only thing that can decrypt them is the DecentSampler plugin itself. In such cases, the only thing that you can do is go into your favorite DAW, play any notes you might want to have as audio files, and export out the audio from that DAW session. This is always my preferred way of operating anyway.

If the library is not copy protected, then you should definitely be able to get at the underlying samples. In fact, it’s pretty easy. There are two formats that DecentSampler libraries come in:

  1. If you are presented with a .dsbundle file, this is really just a directory. If you are on Windows or Linux, you should be able to just look inside that directory and find the sample files. If you are on Mac, this file will show up as a “package.” To get access to it, find the file in the Finder, hold down the Control key, and then click on the file: a context menu will pop up, from which you should select Show Package Contents. From this point on, the .dsbundle file will be presented to you just like any other folder…and somewhere in that folder you will find the raw audio files. The exact location will be different for every library.
  2. If you are presented with a .dslibrary file, then you will need to decompress it. In reality, .dslibrary files are simply .zip files, and if you change their extension from .dslibrary to .zip you should be able to decompress the library just as you would any other .zip file. Within the directory structure that gets created, you should be able to find a folder that contains your samples.

That’s it! Hope this was helpful.

– Dave

Posted on Leave a comment

For Sample Creators: How to use the Wavefolder and Waveshaper effects

Oscilloscope view of a sawtooth wave form that has been folding back on itself.

Decent Sampler v1.7.3 introduces the new wave folder and wave shaper effects. These can be used to add extra harmonic content to your signals (aka distortion). What both of these effects have in common is that they usually sound much better when applied to a single voice rather than to an entire signal. In Decent Sampler, it is possible to apply effects at the voice level by attaching them to groups. Since each group is triggered independently, they do not share effects. In other words, each time you hit a key, a new copy of that voice will be created.

Wave folder

The wave_folder effect allows you to fold a waveform back on itself. This is very useful for generating additional harmonic content. Here is what that looks like in practice:

Oscilloscope view of a sawtooth wave form before wavefolding
Sawtooth waveform before wavefolding
Oscilloscope view of a sawtooth wave form after wavefolding
The same sawtooth wave form after wavefolding

These are the parameters that can be controlled:

AttributeTypeValid RangeDefault
typeRequiredMust be wave_folderwave_folder
driveOptionalThe volume of the input signal1 – 100, where 100 means the signal is amplified by a factor of 100 and 1 means no amplification is applied1
thresholdOptionalThe amplitude above which wave folding should take place0 – 10.00.25
Wavefolder parameters

Because wave folding tends to sound better when applied on a per-voice basis, it usually makes sense to set up the wave folder at the group level (separate group effects get created for each keypress). Example:

<?xml version="1.0" encoding="UTF-8"?>
<DecentSampler pluginVersion="1">
  <ui>
    <tab>
      <labeled-knob x="180" y="40" label="Drive" type="float" minValue="1" maxValue="100" textColor="FF000000" value="1">
        <binding type="effect" level="group" groupIndex="0" effectIndex="1" parameter="FX_DRIVE" translation="linear" />
      </labeled-knob>
      <labeled-knob x="280" y="40" label="Threshold" type="float" minValue="0" maxValue="1" value="1" textColor="FF000000">
        <binding type="effect" level="group" groupIndex="0" effectIndex="1" parameter="FX_THRESHOLD" translation="linear" />
      </labeled-knob>
    </tab>
  </ui>
  <groups>
    <group>
      <!-- samples go here -->
      <effects>
        <effect type="lowpass_4pl" resonance="1" frequency="500" />
        <effect type="wave_folder" drive="1" threshold="1" />
      </effects>
    </group>
  </groups>
  
</DecentSampler>
Code language: HTML, XML (xml)

Waveshaper

The wave_shaper effect allows you to apply standard tanh waveshaping to your input signal. Here are some examples what that looks like in practice:

An oscilloscope display of an example of sine wave before wave shaping is applied.
A sine wave before wave shaping is applied
An oscilloscope display of a sine wave after wave shaping is applied.
A sine wave after wave shaping is applied

There are a few parameters which can be controlled:

AttributeTypeValid RangeDefault
typeRequiredMust be wave_shaperwave_folder
driveOptionalThe amount of distortion. This really just controls the volume of the input signal.1 to 1000 where 1 means no change to the input signal and 1000 means the amplitude is multiplied by a factor of 1000.1
driveBoostOptionalChanges the character of distortion that gets produced0 – 1.00
outputLevelOptionalThe linear output level of the signal0 – 1.00.1
Waveshaper parameters

Because wave shaping tends to sound better when applied on a per-voice basis, it usually makes sense to set up the wave shaper at the group level (separate group effects get created for each keypress). Example:

<DecentSampler pluginVersion="1">
  <ui>
    <tab>
      <labeled-knob x="180" y="40" label="Drive" type="float" minValue="0" maxValue="1000" textColor="FF000000" value="0.5473124980926514">
        <binding type="effect" level="group" groupIndex="0" effectIndex="0" parameter="FX_DRIVE" translation="linear"/>
      </labeled-knob>
      <labeled-knob x="280" y="40" label="Boost" type="float" minValue="0" maxValue="1" value="0.328312486410141" textColor="FF000000">
        <binding type="effect" level="group" groupIndex="0" effectIndex="0" parameter="FX_DRIVE_BOOST" translation="linear"/>
      </labeled-knob>
      <labeled-knob x="380" y="40" label="Output Lvl" type="float" minValue="0" maxValue="1" value="0.1" textColor="FF000000">
        <binding type="effect" level="group" groupIndex="0" effectIndex="0" parameter="FX_OUTPUT_LEVEL" translation="linear"/>
      </labeled-knob>
    </tab>
  </ui>
  <groups>
    <group>
        <em><!-- Samples go here. --></em>
      <effects>
        <effect type="wave_shaper" drive="0.5473124980926514" driveBoost="0.328312486410141" outputLevel="0.1"/>
      </effects>
    </group>
  </groups>
Code language: HTML, XML (xml)

Examples

The examples from this blog post can be download here.

Posted on 16 Comments

For Sample Creators: How to use Convolution in your Decent Sampler presets

A spectrogram of a convolution reverb impulse response.

Version 1.6.12 of Decent Sampler brings a Convolution effect to the Decent Sampler platform. If you don’t know what Convolution is, you can see a great explanation here. The most common use case for convolution is in creating reverb, and that is the use case that will be demonstrated here.

How to add the Convolution effect to a preset

The convolution effect is invoked in much the same way that any other effect is defined:

<effects>
  <effect type="convolution" mix="0.5" irFile="Samples/Hall_IR.wav" />
</effects>Code language: HTML, XML (xml)

As you can see, other than the required type attribute, there are two other attributes:

  • The mix attribute controls how much of the convolved signal is present in the output. A value of 0 is completely dry whereas a value of 1 is completely wet containing only the convolved signal.
  • The irFile attribute specifies the file that should be used as an impulse response or IR.

How to control the convolution effect using UI controls

Two of the convolution effect’s attributes can be controlled using UI controls. The mix level can be controlled by a knob as follows:

<labeled-knob x="680" y="40" label="Conv Mix" type="float" minValue="0" maxValue="1" value="0.5" textColor="FF000000" >
  <binding type="effect" level="instrument" position="0" parameter="FX_MIX" translation="linear"  />
</labeled-knob>Code language: HTML, XML (xml)

The IR impulse can be changed dynamically using a menu control:

<label text="IR File" x="480" y="40" width="120" height="30"></label>
<menu x="580" y="40"  width="120" height="30" requireSelection="true" placeholderText="Choose..." value="1">
  <option name="long hall.wav">
    <binding type="effect" level="instrument" position="1" parameter="FX_IR_FILE" translation="fixed_value" translationValue="Samples/long hall.wav" />
  </option>
  <option name="ABLCR Chord Vocal.aif">
   <binding type="effect" level="instrument" position="1" parameter="FX_IR_FILE" translation="fixed_value" translationValue="Samples/ABLCR Chord Vocal.aif" />
  </option>
  <option name="Amp Spring High.aif">
    <binding type="effect" level="instrument" position="1" parameter="FX_IR_FILE" translation="fixed_value" translationValue="Samples/Amp Spring High.aif" />
  </option>
  <option name="Swede Plate 3.5s.aif">
    <binding type="effect" level="instrument" position="1" parameter="FX_IR_FILE" translation="fixed_value" translationValue="Samples/Swede Plate 3.5s.aif" />
  </option>
</menu>Code language: HTML, XML (xml)

Examples

An example Decent Sampler preset that uses IR reverb can be downloaded here. (You’ll want to check out the example-003-how-to-use-convolution-reverb folder.)

Performance considerations

While convolution is a powerful tool that can go a long way towards shaping a sample library’s sound, it can also be quite costly in terms of CPU usage. Sample creators would do well to create versions both with and without convolution effect and compare the relative CPU usage of the two versions before opting to use convolution.

Posted on 11 Comments

How to add LFOs and extra envelopes to your Decent Sampler instruments

As for version 1.5.24 of Decent Sampler, it is now possible to make use of LFOs and ADSR envelopes in your Decent Sampler sample libraries. In this blog post, we’ll go through how to set these up.

The <modulators> section

This is a new section that 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:

  • shape: controls the oscillator shape. Possible values are sine, square, saw.
  • frequency: The speed of the LFO in cycles per second. For example, a value of 10 would mean that the waveform repeats ten times per second.
  • 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 (default for LFOs) and voice. If voice is chosen, a new LFO is started each time a new note is pressed.

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 bindings 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 of the File Format Reference Guide and 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>

This is Example 1 from the example pack you can download here.

How modulator bindings differ from knob or MIDI bindings

If you’re already familiar with the concept of bindings, then you’ll want to read this section especially careful as you may notice a few difference 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:

  • All gain effect parameters
  • All delay effect parameters
  • All phaser effect parameters
  • All filter effect parameters
  • All reverb effect parameters
  • All chorus effect parameters
  • Group Volume
  • Global Volume
  • Group Pan
  • Global Pan
  • Group Tuning
  • Global Tuning

The new modBehavior parameter for bindings

Another new feature of bindings is the addition of the modBehavior attribute. This controls exactly what effect a binding actually has on the parameter it is targeting. There are three possible values for this:

  • set: This means that the value that is generated by the binding becomes the new value for the parameter being targeted. NOTE: set is the default value and this is the way that knobs and MIDI CC bindings work by default. That being said, it’s usually not the correct choice for modulations such as LFOs and secondary ADSR envelopes.
  • add: The value generated by the binding gets added to the current value of the parameter being targeted.
  • multiply: The value generated by the binding gets multiplied with the current value of the parameter being targeted.

In order to understand what any of this means, let’s look at the following example:

<effects>
    <effect type="lowpass" frequency="60.0"/>
</effects>
<modulators>
    <lfo shape="sine" frequency="2" modAmount="1.0">
        <binding type="effect" level="instrument" position="0" parameter="FX_FILTER_FREQUENCY" translation="linear" translationOutputMin="0" translationOutputMax="2000.0" modBehavior="add" />
    </lfo>
</modulators>

The <lfo> tag above sets up an LFO with a frequency of 2 Hz. It has just one binding, which targets the first global effect, which happens to be a low-pass filter with a cutoff frequency of 60Hz. Every binding can be seen as a pipe that takes an input value, translates that value in some fashion, and then sets a parameter somewhere else in the engine. Here are the steps for this setup:

  1. By default, an LFO generates values between -1.0 and 1.0.
  2. These values then get passed to the binding, which is setup to do a linear translation. This linear translation has a minimum of 0 and maximum of 2000, which means that when the LFO is at its lowest point (-1.0) the binding will generate the number 0 (the minimum) and when the LFO is at its highest point (1.0), the binding will generate the number 2000 (the maximum).
  3. Because the modBehavior value is add, this new value that is generated by the binding will be added to the original cutoff value of 60Hz. This means that when the LFO is at its lowest point, the filter cutoff will be 60Hz (i.e. 60 + 0) and when its at its highest point, the filter cutoff will be 2060Hz (i.e. 60 + 2000).

LFO 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. For example, what if we want to have an envelope that targets a low-pass filter. Let’s say that when we press down on a key, we want that low-pass filter to open up slowly until, 2 seconds later, it reaches its peak. In theory, we could set up something like this:

 

<effects>
    <effect type="lowpass" frequency="60.0"/>
  </effects>
<modulators>
    <envelope attack="2" decay="0" sustain="1" release="0.5" modAmount="1.0">
        <binding type="effect" level="instrument" position="0" parameter="FX_FILTER_FREQUENCY" translation="linear" translationOutputMin="0" translationOutputMax="4000.0" modBehavior="add" />
    </envelope>
</modulators>

But there’s a problem with this: let’s imagine that we hit a note, and then one second into that first note, we hit another note. If we have just a single envelope, that envelope will be half-way through its attack phase when the second key is pressed. Depending on how the envelope is configured, that envelope will either retrigger because of the new keypress (this would be the wrong behavior for the first note which is still being held) or keep going in which case the second note will start half way through its attack phase.

To solve this problem, in such cases, we need tell the engine to create a separate modulator for every keypress. To do this we add a scope="voice" attribute to the modulator as follows:

<envelope attack="2" decay="0" sustain="1" release="0.5" modAmount="1.0" scope="voice">

But wait, there’s another problem! In the scenario above, even if we have separate modulator for every keypress, those voices are still all sharing a single global low-pass filter. If you’ve got several modulators pinned to the same global effect, they are going to be setting and resetting that global effect’s parameters to competing values. The engine is going to be at war with itself of which envelope’s values are the correct setting for the filter’s cutoff. In other words, we need separate effects for each keypress. These can be added by specifying…

…effects at the group level

Adding effects that only apply to a specific group is easy. All you need to do is create an <effects> group that lives underneath the <group> element for the group you want to affect. For example:

<groups>
    <group>
        <!-- A sample -->
        <sample path="Samples/Volca Keys Poly-V127-60-C3.wav" loNote="10" hiNote="83" rootNote="48"/>
        <effects>
            <!-- These effects will only apply to this group -->
            <effect type="lowpass" frequency="22000.0"/>
        </effects>
    </group>
</groups>

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.

How to have knobs control group-level effects

Just as it is possible to have knobs that control instrument-level effects, it is also possible to have them control group level effects. In order to specify a group level effect, set the binding’s level to group, and use groupIndex and effectIndex to specify which specific effect needs to be controlled. Here is an example of this a knob that controls a group-level low-pass filter:

<labeled-knob x="655" y="75" label="Tone" type="float" minValue="0" maxValue="1" value="1">
    <binding type="effect" level="group" groupIndex="0" effectIndex="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>

Putting it all together: an envelope filter that controls a low-pass filter

So, if we put all of this into a real world example, we can code imagine an ADSR envelope that is controlling a low-pass filter as follows:

<?xml version="1.0" encoding="UTF-8"?>
<DecentSampler minVersion="1.6.0">
  <groups>
    <group ampVelTrack="0.0">
      <sample path="Samples/Volca Keys Poly-V127-60-C3.wav" loNote="10" hiNote="83" rootNote="48"/>
      <effects>
        <effect type="lowpass" frequency="22000.0"/>
      </effects>
    </group>
  </groups>
  <modulators>
    <envelope attack="1" decay="0.5" sustain="0" release="0.5" modAmount="1" scope="voice">
      <binding type="effect" level="group" groupIndex="0" effectIndex="0" parameter="FX_FILTER_FREQUENCY" modBehavior="set" translation="table" translationTable="0,33;0.3,150;0.4,450;0.5,1100;0.7,4100;0.9,11000;1.0001,22000"  />
    </envelope>
  </modulators>
</DecentSampler>

This is Example 2 from the example pack.

How to make knobs control modulator parameters

Both types of modulators – <lfo> and <envelope> – have a modAmount parameter. This consists of a value between 0 and 1 that dictates how much the modulation affects the things it is targeting. In conventional terms, this is like the modulation depth. In order to create a knob that controls LFO depth, you would create a knob that targets a modulator’s depth. Here’s how you would do this:

<labeled-knob x="585" y="75" label="LFO Depth" type="float" minValue="0.0" maxValue="1" value="1" >
    <binding level="instrument" type="modulator" position="0" parameter="MOD_AMOUNT" />
</labeled-knob>

Note the binding type value of modulator and a position of 0. In other words, we are targeting the first modulator in the modulator block. The parameter we are targeting is MOD_AMOUNT.

It is similarly possible to target LFO rate using a parameter value of FREQUENCY:

<labeled-knob x="655" y="75" label="LFO Rate" type="float" minValue="0.0" maxValue="10" value="1">
   <binding level="instrument" type="modulator" position="0" parameter="FREQUENCY" />
</labeled-knob>Code language: HTML, XML (xml)

You can see a full example of a patch that controls rate and depth in Example 3 of the example pack.

Conclusion

That’s pretty much it. We look forward to seeing what you do with LFOs and envelopes. Make sure you download the example pack from here.

The example pack contains the following examples:

  • Example 1 shows how to make an LFO that controls a global lowpass filter
  • Example 2 shows how to have a voice-level envelope which controls a group-level filter
  • Example 3 shows how to have knobs control LFO parameters
  • Example 4 shows how to have knobs control envelope parameters
  • Example 5 shows how to modulate group volumes
  • Example 6 shows how to modulate group panning
  • Example 7 shows how to modulate group tuning
Posted on 10 Comments

Dropdown Menus, Colored Keys, and Keyswitches come to Decent Sampler

An example of the key coloring functionality

Version 1.4 of Decent Sampler recently got released: Download it here.

It brings with it a number of under-the-hood features that sample developers can make use of:

Colored Keys

It’s now possible to color the keys of the on-screen keyboard.

This can be useful for showing different ranges of notes that serve different purposes or highlighting notes used as keyswitches. In order to implement colored keys, make use of the new <keyboard> and <color> elements as follows:

<DecentSampler>
    <ui>
        <em><!-- Other stuffhere --></em>
        <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>
    <em><!-- Other stuff here --></em>
</DecentSampler>Code language: HTML, XML (xml)

By default, Decent Sampler highlights all of the notes that are mapped for a given sample. If you use the color keys feature, this default highlighting will be turned off and it will be up to you to color whatever keys you want.

Full documentation for the new elements is here.

Dropdown Menus

In order to implemented dropdown menus, use the new <menu> and <option> elements. The <menu> element defines where the dropdown menu will show up in the ui, whereas the <option> XML elements determine what menu options it has and what if anything those options actually do:

<menu x="10" y="40" width="120" height="30" value="2">
  <option name="Menu Option 1">
    <!-- 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">
    <!-- 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>Code language: HTML, XML (xml)

In this example, a menu is being used to switch between two groups (the first menu option turns group 0 on and group 1 off; the section option turns group 0 off and group 1 on). Full documentation for the new <menu> and <option> elements is here.

The new fixed_value translation type

You’ll note, in the example above, there’s something new in the bindings: the four bindings elements have a translation parameter of type fixed_value. This is a new translation type. Up until now, binding translation has strictly been about taking an input parameter (such as a knob value or continuous controller amount) and translating it so that it is useful for some other purpose (it’s our way of being able to do a little bit of math without having a full-blown scripting language). This new fixed_value binding is different. It ignores the input value completely and instead provides whatever is specified in the translationValue parameter. In this way, each menu option can have hardcoded values that it provides its bindings when it is selected.

Keyswitches

It is now possible to implement keyswitches. For a long time, it’s been possible to trigger events when a MIDI continuous controller event is received: using MIDI CCs we can change knob values or group volumes, for example. It is now possible to trigger events using MIDI notes as well. Here’s what the setup for a MIDI note-based event mapping would look like:

<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>Code language: HTML, XML (xml)

In this 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.

More documentation on this can be found here.