Manual for SFZ to HISE converter / translator

Online Manual for SFZ to HISE converter / translator application. (latest version)

For version: 0.5.2. Updated: 2023-02-16. Written by: Anders Eklöv.

Introduction

The SFZ to HISE converter is a standalone tool, made to support translation from the SFZ sampler format (.sfz) to the HISE Samplemap format (.xml). While the included SFZ importer inside HISE is good, this tool aims to first provide a parser of the SFZ language, with support for more data output via a side-car JSON object literal. After conversion you have the option to copy that JSON object to a file for import in either HISE itself (just place in a file or variable) or other programming languages altogether, such as JavaScript, C++, Python, Lua or whatever you would use.

The idea was to process more SFZ opcodes than what HISE samplemaps will support, but also to use fallback for opcodes set at the <group> or <global> level and omitted at the <region> level. For all supported region opcodes you can set things like hivel, lovel, hikey or lokey at the group or global level and have that reflected in all samples included in the group, or if no opcode is set on the group level, it looks for one on the higher, global level.

SFZ format, lines and formatting

The SFZ format is very versatile and can be written in many ways. This presents a problem in some cases where there is more than one header on one line. It is therefore best to keep one header on one line or more.

For example this would produce unpredictable results:

<region> sample="path/to/file.wav" key=22 <region> sample="file.wav"

But this would be fine:

<region>
sample="path/to/file.wav" key=22
<region
sample="file.wav"
key=23

There is no maximum amount of lines that you can use for a header, when the parser reaches the next header it will run the previous one and extract any opcodes found. This search happens per line in the document and is the reason for errors being likely if more than one header is found on a line, especially when searching (using regex) for sample opcodes.

Audio formats supported

By default the parser looks for audio files in the formats .wav, .aiff, .aif and .flac in either lower- or uppercase form, which are common audio file formats used in SFZ instruments. This application does not currently change the audio file ending. Use any text editor to search-replace any non HISE supported audio formats either before or after the conversion along side potential audio conversion of the files themselves.

The HISE samplemap creator function of the application will turn any uppercase file-endings into lowercase equivalents, like turning .AIFF into .aiff.

File paths are also pre-processed to remove os specific characters, like C:\ or just backslashes \ are all removed and turned into single forward slashes /.

SFZ opcode data – supported and unsupported

SFZ is an extensive format with many options. HISE only supports a handful of the most important ones.

The supported opcodes are: like [sfz opcode (optional sfz alias) = “HISE equivalent”]

  • sample = “FileName”.
  • key (or alias pitch_keycenter) = “Root”.
  • lokey = “LoKey”.
  • hikey = “HiKey”.
  • lovel = “LoVel”.
  • hivel = “HiVel”.
  • volume = “Volume”. Note: “group_volume” can be found in object.group.basic[id] object, explained below. Can be used in your scripting or copied from there.
  • pan = “Pan”.
  • tune = “Pitch”.
  • offset = “SampleStart”.
  • end = “SampleEnd”.
  • loop_mode (or alias loopmode) = “LoopEnabled”.
  • loop_start (or alias loopstart) = “LoopStart”.
  • loop_end (or alias loopend) = “LoopEnd”.

All opcodes go into the JS / JSON object

All the opcodes that the converter finds, supported or not, is entered into a complete collection of all opcodes recognized, internally in the JavaScript application called the extendedOpcodesOutput object literal, copyable to the clipboard with the click of a button as either the raw JSON object or inside a variable, like this: var sfz_to_hise_extended_object = {data here}; (for easy copy-paste into a document). We’ll refer to this internal and copyable object as just object.

This object has keys with the names of the major SFZ headers. For each header you will find a nested object with 2 sub-keys, called basic and extended. The basic key contains all opcodes found that HISE supports, while extended is used for objects or arrays containing the opcodes that HISE samplemaps do not support. As much data as possible is supposed to be able to be used in your own scripting, at least that is the point of the data extraction.

The SFZ opcodes supported by HISE are stored in:

  • object.global.basic
  • object.group.basic
  • object.region.basic

The opcode data that is not supported in HISE maps is saved to the following object properties:

  • object.global.extended
  • object.group.extended
  • object.region.extended

The reason for choosing this structure, where non-supported (extended) opcodes is separate in a synced list, is that there might be an overwhelming amount of data in some SFZ documents and having all the HISE supported opcode data (used for samplemaps) in the same place would be unnecessary. It makes readability of the object object better.

All regions entered into the region.basic are syncronized with (in the same order of) the regions in region.extended, and both objects contain the gr_id (group id) and region_id (the region/sample id as it was found in the SFZ file, starting at id 0) for easy synchonization. By default regions are keys with the id and an object as the value, like "12": { opcode: "value" }, but you can override this with an array of objects in the user settings, noted below.

User settings

Along side the selection of a file on your hard drive you have a couple of options for the processing of the SFZ file, the output of the HISE samplemap and the extended opcodes data JSON object.

Debug mode

Outputs an extensive log of messages in the browser’s Developer Tools, under Console. Use with smaller documents, as large (1000 lines +) will take a lot of time to process for a browser due to console.log messages being time and resource consuming. For that reason, string concatenation is used heavily in the javascript application and output to the log only in ends of runs, which is more efficient. Google Chrome is fastest, but Firefox is good too.

Sample path prefix

Fill in any path you want prepended to the sample path/file.x. Entering my-prefix/ gives my-prefix/path/file.x.

Choose behaviour in case of no value found for a HISE tag

Sometimes a value cannot be asserted for an opcode. When nothing is found you can choose the behaviour. Either “empty string” (Volume=””) or “omit tag altogether” (nothing is inserted at all).

Use region opcode ‘seq_position’ as Round Robin groups

If the SFZ file uses round robins via seq_position (region level) and seq_length (group level), you can use this as the HISE RRGroup value, instead of the group id number the sample/region was found under. Setting the round robin functionality is later set in HISE-script using a statement in the main init script.

Use array instead of object and keys for regions/samples

When creating the JSON object’s list of regions (sample zones), the default is to use the structure object -> "key": object. For iterating in some languages in an easier fashion, use this option to instead use array -> object. This creates an array of objects.

The default setting uses object keys as ids:

"region": {
    "basic": {
        "0": {
            "sample": "my-file.wav",
            "path": "samples-folder/",
            "key": "22",
            "lokey": "21",
            "hikey": "23",
            ... ... 
            "gr_id": 0,
            "region_id": 0
        }, 
        "1": {
            next region... 
            "gr_id": 0,
            "region_id": 1
        }
    }
}

This can be iterated through using a for (key in object) loop in JS (in a browser or nodejs) or HISE-script.

Ticking this option uses array instead:

"region": { 
    "basic": [
        {
            "sample": "my-file.wav",
            "path": "samples-folder/",
            "key": "22",
            "lokey": "21",
            "hikey": "23",
            ... ... 
            "gr_id": 0,
            "region_id": 0
        }, 
        {
            next region... 
            "gr_id": 0,
            "region_id": 1
        }
    ]
}

With the output in array-form a normal for (var i = 0; i < length; i++) loop is a given choice.

Opcode hierarchy and fallback values

Samples should have their own opcodes set, but the SFZ language is very flexible in letting you set values for multiple files at once, such as on the group, global, control or master headers. This tool currently includes for 3 header levels to try to find a value for a sample, given that a HISE samplemap supported opcode is not present on the region in question. Current hierarchy:

  1. <region>
  2. <group>
  3. <global>

If no present values are found, the output is determined by the user setting “if no value found for a HISE tag“, which lets you choose how to handle empty or non-present values in the SFZ file.

Key root, low key and high key

During extraction/parsing the application tries to automatically anticipate what the proper action should be if either the root, hi key or low key elements (governing the mapping of the samples) are not present. The main root key for the mapping is the SFZ key opcode, or the equivalent opcode pitch_keycenter, used in conjunction with hikey and lokey is the way to set sample mappings in SFZ. If any of these are missing, the default behaviour is to look for the alias on the region level, followed by the hierarchy above. If no value is found for this essential component, the Root assignment for the sample in the HISE samplemap will be an average of either an existing hikey and lokey or all three are set to the one of them that can be found. If nothing is found, they all come out empty, following the user setting “if no value found for a HISE tag“.

High and Low velocity

The same procedure is used for finding the highest and lowest velocity mappings for a sample. Region, group and global is used to fall back onto a global value for each opcode. If nothing is found in any header level, the default is LoVel=0 and HiVel=127.


The support for SFZ headers and opcodes is mainly focused on hise supported things so far, but will be expanded on later.

Using the application can be done to extract information from an SFZ document only, without using the conversion to HISE samplemaps. The JSON object contains all the information regognized as opcode data, so you could use it to translate into other formats as well, or use the data for other purposes.

For questions or bug-reports, contact the author Anders Eklöv via Twitter or here via support.

Download this manual (md/pdf/rtf/html)

Go to SFZ to HISE converter application | Go back to resources

Our Cookie & Privacy Policy
Hey, we use cookies to improve user experience. Please accept our Cookie Policy and keep reading.
Learn more