Skip to content
9 changes: 9 additions & 0 deletions documentation/README-FORMATS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ The following multi-sample formats are supported:
* [DecentSampler](#decentsampler)
* [discoDSP Bliss](#discodsp-bliss)
* [Expert Sleepers disting EX](#expert-sleepers-disting-ex)
* [Fairlight CMI 3](#kontakt-nkinkm)
* [Kontakt NKI/NKM](#kontakt-nkinkm)
* [Korg KSC/KMP/KSF](#korg-ksckmpksf)
* [Korg wavestate/modwave](#korg-wavestatemodwave)
Expand Down Expand Up @@ -216,6 +217,14 @@ The basic multi-sample setup is encoded in the file-names of the samples. Furthe
* Re-sample to 16bit/44.1kHz: If enabled, samples will be resampled to 16bit and 44.1kHz. While the device can play higher resolutions as well it decrease the number of voices it can play.
* Trim sample to range of zone start to end: Since the format does not support a sample start attribute, this fixes the issue.

## Fairlight CMI 3

We've all heard stories about and uses of the Fairlight CMI IIx and earlier. The Series III was one of the first 16-bit samplers, second only to the Synclavier. Extensive reverse engineering effort of the self-contained voice format was applied to make it available as a source format, but unfortunately, current constraints combined with the strict third party user community makes it unfeasible to use as a destination format at this time.

Note that this will not work with IIx or earlier voices despite the same VC extension used.

Filter parameters are currently not supported, but then, as a variable clock DAC sampler, the original hardware had no interpolation anyway.

## Kontakt NKI/NKM

Kontakt is a sampler from Native Instruments which uses a plethora of file formats which all are sadly proprietary and therefore no documentation is publicly available. Nevertheless, several people analyzed the format and by now sufficient information is available to provide the support as the source.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import de.mossgrabers.convertwithmoss.format.kmp.KMPDetector;
import de.mossgrabers.convertwithmoss.format.korgmultisample.KorgmultisampleCreator;
import de.mossgrabers.convertwithmoss.format.korgmultisample.KorgmultisampleDetector;
import de.mossgrabers.convertwithmoss.format.cmi3.VCDetector;
import de.mossgrabers.convertwithmoss.format.music1010.bento.BentoCreator;
import de.mossgrabers.convertwithmoss.format.music1010.bento.BentoDetector;
import de.mossgrabers.convertwithmoss.format.music1010.blackbox.Music1010Creator;
Expand Down Expand Up @@ -119,6 +120,7 @@ public ConverterBackend (final INotifier notifier)
new TX16WxDetector (notifier),
new DecentSamplerDetector (notifier),
new DistingExDetector (notifier),
new VCDetector (notifier),
new IsoDetector (notifier),
new KontaktDetector (notifier),
new KMPDetector (notifier),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Written by Jürgen Moßgraber - mossgrabers.de
// (c) 2019-2024
// Licensed under LGPLv3 - http://www.gnu.org/licenses/lgpl-3.0.txt

package de.mossgrabers.convertwithmoss.format.cmi3;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.function.Consumer;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

import de.mossgrabers.convertwithmoss.core.IMultisampleSource;
import de.mossgrabers.convertwithmoss.core.INotifier;
import de.mossgrabers.convertwithmoss.core.detector.AbstractDetector;
import de.mossgrabers.convertwithmoss.core.detector.DefaultMultisampleSource;
import de.mossgrabers.convertwithmoss.core.model.IGroup;
import de.mossgrabers.convertwithmoss.core.model.IMetadata;
import de.mossgrabers.convertwithmoss.core.model.ISampleData;
import de.mossgrabers.convertwithmoss.core.model.ISampleLoop;
import de.mossgrabers.convertwithmoss.core.model.ISampleZone;
import de.mossgrabers.convertwithmoss.core.model.implementation.DefaultGroup;
import de.mossgrabers.convertwithmoss.core.model.implementation.DefaultSampleLoop;
import de.mossgrabers.convertwithmoss.core.model.implementation.DefaultSampleZone;
import de.mossgrabers.convertwithmoss.core.settings.MetadataSettingsUI;
import de.mossgrabers.convertwithmoss.exception.ParseException;
import de.mossgrabers.convertwithmoss.file.AudioFileUtils;
import de.mossgrabers.tools.ui.Functions;


/**
* Descriptor for Fairlight CMI3 Voice (VC) files detector.
*
* @author Jürgen Moßgraber
*/
public class VCDetector extends AbstractDetector<VCDetectorUI>
{
private static final String [] VC_ENDINGS =
{
".vc",
".VC"
};

/**
* Constructor.
*
* @param notifier The notifier
*/
public VCDetector (final INotifier notifier)
{
super ("Fairlight CMI3 Voice", "VC", notifier, new VCDetectorUI ("VC"));
}


/** {@inheritDoc} */
@Override
protected void configureFileEndings (final boolean detectPerformances)
{
this.fileEndings = VC_ENDINGS;
}

/** {@inheritDoc} */
@Override
protected List<IMultisampleSource> readPresetFile (final File sourceFile)
{
final List<IMultisampleSource> multiSampleSources = new ArrayList<> ();
multiSampleSources.addAll(this.readVCFile(sourceFile));

return multiSampleSources;
}


/**
* Reads a VC file and creates a multi-sample source from it.
*
* @param sourceFile The VC file
* @return The multi-sample source if found
*/
private List<IMultisampleSource> readVCFile (final File sourceFile)
{
final List<IMultisampleSource> multiSampleSources = new ArrayList<> ();
try (final FileInputStream stream = new FileInputStream (sourceFile))
{
final VCFile vcFile = new VCFile (this.notifier, sourceFile);
multiSampleSources.addAll(vcFile.read (stream, sourceFile));
}
catch (final IOException | ParseException ex)
{
this.notifier.logError ("IDS_ERR_SOURCE_FORMAT_NOT_SUPPORTED", ex);
return Collections.emptyList ();
}
return multiSampleSources;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Written by Jürgen Moßgraber - mossgrabers.de
// (c) 2019-2025
// Licensed under LGPLv3 - http://www.gnu.org/licenses/lgpl-3.0.txt

package de.mossgrabers.convertwithmoss.format.cmi3;

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

import de.mossgrabers.convertwithmoss.core.INotifier;
import de.mossgrabers.convertwithmoss.core.settings.MetadataSettingsUI;
import de.mossgrabers.tools.ui.BasicConfig;
import de.mossgrabers.tools.ui.panel.BoxPanel;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ScrollPane;


/**
* Settings for the CMI3 detector.
*
* @author Jürgen Moßgraber
*/
public class VCDetectorUI extends MetadataSettingsUI
{


/**
* Constructor.
*
* @param prefix The prefix to use for the properties tags
*/
public VCDetectorUI (final String prefix)
{
super (prefix);
}


/** {@inheritDoc} */
@Override
public Node getEditPane ()
{
final BoxPanel panel = new BoxPanel (Orientation.VERTICAL);

////////////////////////////////////////////////////////////
// Options

////////////////////////////////////////////////////////////
// Metadata

this.addTo (panel);
this.getSeparator ().getStyleClass ().add ("titled-separator-pane");

final ScrollPane scrollPane = new ScrollPane (panel.getPane ());
scrollPane.fitToWidthProperty ().set (true);
scrollPane.fitToHeightProperty ().set (true);
return scrollPane;
}


/** {@inheritDoc} */
@Override
public void saveSettings (final BasicConfig config)
{
super.saveSettings (config);
}


/** {@inheritDoc} */
@Override
public void loadSettings (final BasicConfig config)
{
super.loadSettings (config);
}


/** {@inheritDoc} */
@Override
public boolean checkSettingsUI (final INotifier notifier)
{
if (!super.checkSettingsUI (notifier))
return false;

return true;
}


/** {@inheritDoc} */
@Override
public boolean checkSettingsCLI (INotifier notifier, Map<String, String> parameters)
{
if (!super.checkSettingsCLI (notifier, parameters))
return false;

return true;
}


/** {@inheritDoc} */
@Override
public String [] getCLIParameterNames ()
{
final List<String> parameterNames = new ArrayList<> (Arrays.asList (super.getCLIParameterNames ()));
return parameterNames.toArray (new String [parameterNames.size ()]);
}
}
Loading