Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion documentation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
## 19.0.0 (unreleased)

* New: Improved user interface for long lists of formats.
* New: Added support for the Polyend Tracker (PTI) instrument format (thanks to Douglas Carmichael).
* New: Added support for the Elektron Tonverk preset (TVPST) format - read (One-Shot, Multi and Drum machines, including amplitude and filter envelopes whose normalized times are mapped to seconds with a warped-exponential curve calibrated against hardware resamples) and write (Multi or Drum machine). Writing mirrors the device's SD-card layout: the preset is stored as a flat file in 'User/Presets' and its samples in 'User/Multi-sampled Instruments/<name>', referenced by their absolute device path, so the created 'User' folder can be copied straight onto the Tonverk (thanks to Douglas Carmichael).
* New: The Elektron Tonverk multi-sample mapping format (.elmulti/.eldrum) is now labelled "Elektron Tonverk Multisample" consistently for both reading and writing - it was previously shown as "Elektron Multi" as a source but "Elektron Tonverk" as a destination, the latter being easily confused with "Elektron Tonverk Preset" (thanks to Douglas Carmichael).
* New: Added support for the Renoise instrument (XRNI) format (thanks to Douglas Carmichael).
* New: Added support for the Synthstrom Deluge instrument format (thanks to Douglas Carmichael).
* New: Added support for the Downloadable Sound format (DLS) - read only.
* New: Added several new tags for category detection.
* Elektron Tonverk Multisample (thanks to Douglas Carmichael)
* Fixed: Loops were dropped when reading the multi-sample mapping (.elmulti/.eldrum) format - the loop was parsed but never attached to the sample zone, so converted instruments lost their loop.
* Fixed: A mapping slot without explicit sample-trim points read a sample start and end of -1 instead of the whole sample (e.g. a converted Waldorf QPAT then showed a sample start and end of -1 on the device).
* FLAC/OGG
* Fixed: FLAC or OGG samples stored inside a ZIP archive (e.g. discoDSP Bliss or DecentSampler libraries) could fail to decompress.
* Fixed: Stereo (multi-channel) samples stored in a compressed format were truncated to half their length when decompressed while writing to an uncompressed destination.
Expand Down
28 changes: 26 additions & 2 deletions documentation/README-FORMATS.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,40 @@ There is no write support.
## Elektron Tonverk

The Elektron Tonverk is a dedicated hardware sampler that marks an important milestone for Elektron as its first instrument to support multi-samples. This allows users to map multiple sampled sounds across keys or velocity ranges, creating more expressive and realistic instruments than single-sample playback alone.
Sadly, the elmulti format is very basic and limited. It only supports the basic multi-sample layout does not contain any synthesizer parameters like envelopes or filter settings.

ConvertWithMoss supports two Elektron Tonverk formats: the basic multi-sample mapping files (*.elmulti / *.eldrum) and the full preset (*.tvpst).

### Multi-Sample Mapping (.elmulti / .eldrum)

The elmulti format is very basic and limited. It only supports the basic multi-sample layout and does not contain any synthesizer parameters like envelopes or filter settings.
Furthermore, even this basic setup has some limitations:

* There are no key ranges, the Tonverk always plays the sample with the closest root note. This can lead to different key-ranges than in the source multi-sample.
* Velocity layers are fixed to the key-ranges (like on the modern Akai MPCs).
* Duplicated velocity layers always result in round-robin of these samples (they do not sound at the same time).
* Only 1 Pitch per key zone can be set which means you cannot tune individual samples.

### Destination Options
#### Destination Options

* Re-sample to 24bit/48kHz: If enabled, samples will be resampled to 24bit and 48kHz. While the device can play other resolutions as well, there are reports of issues when you do so.

### Preset (.tvpst)

In contrast to the mapping files, a Tonverk preset is a full sound that also contains the synthesizer parameters. All three generator machines are read:

* **Multi**: a multi-sample mapped to key- and velocity-ranges.
* **One-Shot**: a single sample mapped across the whole keyboard.
* **Drum**: a kit of eight drum voices, each on its own key with its own settings.

The amplitude envelope (AHD or ADSR), the multi-mode filter together with its envelope, the sample loops, gain and panning are converted. The remaining, synthesizer-specific parameters (arpeggiator, effects, global LFOs and the modulation matrix) have no equivalent in the multi-sample model and are therefore not converted.

When writing, the samples are stored next to the preset and referenced by their relative file name, so the preset can be copied anywhere onto the SD card. The full parameter block is created from a neutral factory template (effects bypassed, LFOs, arpeggiator and modulation neutralized) and only the converted parameters above are filled in from the source.

Note: the Tonverk stores envelope times and the filter cut-off frequency as normalized values using internal, non-published curves. ConvertWithMoss uses documented approximations for these. A Tonverk-to-Tonverk conversion is therefore loss-less, while a conversion to or from a unit-based format (such as Waldorf Quantum/Iridium or the Synthstrom Deluge) is a close approximation.

#### Destination Options

* Output Engine: Selects which machine to write. *Multi-Sample* and *Drum Kit* force that machine; *Auto (from source)* writes a Drum machine when the source looks like a drum kit (a percussion category or up to eight single-key zones) and a Multi machine otherwise.
* Re-sample to 24bit/48kHz: If enabled, samples will be resampled to 24bit and 48kHz. While the device can play other resolutions as well, there are reports of issues when you do so.

## Ensoniq EPS/EPS16+/ASR-10
Expand Down
Binary file modified documentation/SupportedFeaturesSampleFormats.ods
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@
import de.mossgrabers.convertwithmoss.format.disting.DistingExCreator;
import de.mossgrabers.convertwithmoss.format.disting.DistingExDetector;
import de.mossgrabers.convertwithmoss.format.dls.DlsDetector;
import de.mossgrabers.convertwithmoss.format.elektron.ElektronMultiCreator;
import de.mossgrabers.convertwithmoss.format.elektron.ElektronMultiDetector;
import de.mossgrabers.convertwithmoss.format.elektron.TonverkMultiCreator;
import de.mossgrabers.convertwithmoss.format.elektron.TonverkMultiDetector;
import de.mossgrabers.convertwithmoss.format.elektron.TonverkPresetCreator;
import de.mossgrabers.convertwithmoss.format.elektron.TonverkPresetDetector;
import de.mossgrabers.convertwithmoss.format.ensoniq.epsasr.EnsoniqEpsAsrDetector;
import de.mossgrabers.convertwithmoss.format.ensoniq.mirage.MirageDetector;
import de.mossgrabers.convertwithmoss.format.exs.EXS24Creator;
Expand Down Expand Up @@ -144,7 +146,8 @@ public ConverterBackend (final INotifier notifier)
new DecentSamplerDetector (notifier),
new DlsDetector (notifier),
new DistingExDetector (notifier),
new ElektronMultiDetector (notifier),
new TonverkMultiDetector (notifier),
new TonverkPresetDetector (notifier),
new EnsoniqEpsAsrDetector (notifier),
new MirageDetector (notifier),
new IsoDetector (notifier),
Expand Down Expand Up @@ -179,7 +182,8 @@ public ConverterBackend (final INotifier notifier)
new TX16WxCreator (notifier),
new DecentSamplerCreator (notifier),
new DistingExCreator (notifier),
new ElektronMultiCreator (notifier),
new TonverkMultiCreator (notifier),
new TonverkPresetCreator (notifier),
new KMPCreator (notifier),
new KorgmultisampleCreator (notifier),
new EXS24Creator (notifier),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
import de.mossgrabers.convertwithmoss.file.riff.CommonRiffChunkId;
import de.mossgrabers.convertwithmoss.file.wav.WaveFile;
import de.mossgrabers.convertwithmoss.file.wav.WaveRiffChunkId;
import de.mossgrabers.convertwithmoss.format.elektron.ElektronMultiFile.ElektronKeyZone;
import de.mossgrabers.convertwithmoss.format.elektron.ElektronMultiFile.ElektronSampleSlot;
import de.mossgrabers.convertwithmoss.format.elektron.ElektronMultiFile.ElektronVelocityLayer;
import de.mossgrabers.convertwithmoss.format.elektron.TonverkMultiFile.TonverkKeyZone;
import de.mossgrabers.convertwithmoss.format.elektron.TonverkMultiFile.TonverkSampleSlot;
import de.mossgrabers.convertwithmoss.format.elektron.TonverkMultiFile.TonverkVelocityLayer;
import de.mossgrabers.tools.ui.Functions;


Expand All @@ -38,7 +38,7 @@
*
* @author Jürgen Moßgraber
*/
public class ElektronMultiCreator extends AbstractWavCreator<ElektronMultiCreatorUI>
public class TonverkMultiCreator extends AbstractWavCreator<TonverkMultiCreatorUI>
{
/**
* The factory default velocity. The Tonverk rejects the whole preset file if a velocity layer
Expand Down Expand Up @@ -74,9 +74,9 @@ public class ElektronMultiCreator extends AbstractWavCreator<ElektronMultiCreato
*
* @param notifier The notifier
*/
public ElektronMultiCreator (final INotifier notifier)
public TonverkMultiCreator (final INotifier notifier)
{
super ("Elektron Tonverk", "Emulti", notifier, new ElektronMultiCreatorUI ("Emulti"));
super ("Elektron Tonverk Multisample", "Emulti", notifier, new TonverkMultiCreatorUI ("Emulti"));
}


Expand Down Expand Up @@ -112,7 +112,7 @@ public void createPreset (final File destinationFolder, final IMultisampleSource

// Create the preset file - must be done after the samples were written since trimming
// does update the zone/loop positions!
final ElektronMultiFile elektronMulti = createPreset (multisampleSource);
final TonverkMultiFile elektronMulti = createPreset (multisampleSource);
final String presetFile = presetName + ".elmulti";
this.notifier.log ("IDS_NOTIFY_STORING", presetFile);
elektronMulti.write (new File (presetFolder, presetFile).toPath ());
Expand Down Expand Up @@ -167,7 +167,7 @@ protected void rewriteFile (final IMultisampleSource multisampleSource, final IS
* @param multiSampleSource The multi-sample source
* @throws IOException Could not read the audio metadata of a sample
*/
private static void prepareZones (final String presetName, final IMultisampleSource multiSampleSource) throws IOException
static void prepareZones (final String presetName, final IMultisampleSource multiSampleSource) throws IOException
{
for (final Entry<Integer, TreeMap<Integer, List<ISampleZone>>> velocityLayerMapEntry: multiSampleSource.getOrderedSampleZones (false).entrySet ())
{
Expand All @@ -179,7 +179,7 @@ private static void prepareZones (final String presetName, final IMultisampleSou
for (int roundRobinIndex = 0; roundRobinIndex < sampleZones.size (); roundRobinIndex++)
{
final ISampleZone zone = sampleZones.get (roundRobinIndex);
zone.setName (ElektronMultiFile.createSampleName (presetName, velocityLayerIndex, keyRoot, roundRobinIndex));
zone.setName (TonverkMultiFile.createSampleName (presetName, velocityLayerIndex, keyRoot, roundRobinIndex));

final ISampleData sampleData = zone.getSampleData ();
if (sampleData == null)
Expand All @@ -199,14 +199,14 @@ private static void prepareZones (final String presetName, final IMultisampleSou
}


private static ElektronMultiFile createPreset (final IMultisampleSource multiSampleSource)
static TonverkMultiFile createPreset (final IMultisampleSource multiSampleSource)
{
final ElektronMultiFile elektronMulti = new ElektronMultiFile ();
final TonverkMultiFile elektronMulti = new TonverkMultiFile ();
elektronMulti.name = multiSampleSource.getName ();

for (final Entry<Integer, TreeMap<Integer, List<ISampleZone>>> velocityLayerMapEntry: multiSampleSource.getOrderedSampleZones (false).entrySet ())
{
final ElektronKeyZone keyZone = new ElektronKeyZone ();
final TonverkKeyZone keyZone = new TonverkKeyZone ();
elektronMulti.keyZones.add (keyZone);

final int keyRoot = Math.clamp (velocityLayerMapEntry.getKey ().intValue (), 0, 127);
Expand All @@ -217,7 +217,7 @@ private static ElektronMultiFile createPreset (final IMultisampleSource multiSam

for (final Entry<Integer, List<ISampleZone>> sampleZonesEntry: velocityLayerMapEntry.getValue ().entrySet ())
{
final ElektronVelocityLayer velocityLayer = new ElektronVelocityLayer ();
final TonverkVelocityLayer velocityLayer = new TonverkVelocityLayer ();
keyZone.velocityLayers.add (velocityLayer);

// The Tonverk rejects a velocity of exactly 0.0, use the factory default instead
Expand All @@ -226,7 +226,7 @@ private static ElektronMultiFile createPreset (final IMultisampleSource multiSam

for (final ISampleZone sampleZone: sampleZonesEntry.getValue ())
{
final ElektronSampleSlot sampleSlot = new ElektronSampleSlot ();
final TonverkSampleSlot sampleSlot = new TonverkSampleSlot ();
velocityLayer.sampleSlots.add (sampleSlot);

// Must be identical to the file name created in writeSamples!
Expand Down Expand Up @@ -267,7 +267,7 @@ else if (tuning.doubleValue () != sampleZone.getTuning ())
}


private static boolean hasLoop (final ISampleZone zone)
static boolean hasLoop (final ISampleZone zone)
{
final List<ISampleLoop> loops = zone.getLoops ();
if (loops.isEmpty ())
Expand All @@ -287,7 +287,7 @@ private static boolean hasLoop (final ISampleZone zone)
* @param multisampleSource The multi-sample source
* @throws IOException Could not retrieve the current sample rate
*/
private static void recalculateForResample (final IMultisampleSource multisampleSource) throws IOException
static void recalculateForResample (final IMultisampleSource multisampleSource) throws IOException
{
for (final IGroup group: multisampleSource.getGroups ())
for (final ISampleZone zone: group.getSampleZones ())
Expand Down Expand Up @@ -341,7 +341,7 @@ private static void recalculateForResample (final IMultisampleSource multisample
*
* @param zone The zone
*/
private static void clampLoops (final ISampleZone zone)
static void clampLoops (final ISampleZone zone)
{
final int lastIndex = zone.getStop () - 1;
if (lastIndex < 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*
* @author Jürgen Moßgraber
*/
public class ElektronMultiCreatorUI extends WavChunkSettingsUI
public class TonverkMultiCreatorUI extends WavChunkSettingsUI
{
private static final String RESAMPLE_TO_24_48 = "ResampleTo2448";

Expand All @@ -38,7 +38,7 @@ public class ElektronMultiCreatorUI extends WavChunkSettingsUI
*
* @param prefix The prefix to use for the identifier
*/
public ElektronMultiCreatorUI (final String prefix)
public TonverkMultiCreatorUI (final String prefix)
{
// Only the sample chunk is enabled by default: the Tonverk factory WAV files contain only
// 'fmt ', 'data' and 'smpl' chunks and the Tonverk WAV parser is strict
Expand Down
Loading