LinuxSampler 2.4.0

LinuxSampler 2.4.0

LinuxSampler 2.4.0 and friends were released on Jun 2nd 2025. A bit more than a year has passed since the previous feature release.

Support for ARM Architecture

This release adds support for the ARM architecture, both for modern 64-bit ARM CPUs (or SoCs) and legacy 32-bit ARM CPUs, minimum requirement is an ARMv6 (32-bit) CPU. No additional patches are required anymore to run LinuxSampler on ARM.

NKSP Language Extensions

The NKSP real-time instrument script language was extended with major new features on language level:

Local Variables

The NKSP language supports now local variables by declaring variables with the new local specifier keyword. Local variables are variables on the virtual machine's (VM) data stack which only exist within the current scope, like within the body of the current NKSP event handler or NKSP user function:

on controller declare local $foo := 1 { scope of local variable $foo ends here } end on

These local variables can reduce code complexity of instrument scripts tremendously, as they effectively prevent side effects with other script instances and threads (e.g. via fork() call) that may happen with global script variables as they are accesssed concurrently. So far polyphonic variables could be used to mitigate such concurrency issues, however local variables finally provide a clean approach to handle such issues more appropriately.

Arguments and Result for User Functions

As a logical consequence, user declared NSKP functions support now function arguments and return values:

function myFn(??arguments??) -> ??result?? { ... } end function

For example arguments and return value of integer data type, i.e. the following function returns the sum of parameters passed:

function sumUp($a, $b, $c) -> $d { $a, $b, $c are arguments passed to this user function, whereas ... } $d := $a + $b + $c { ... $d is the result value to be returned to caller of this function } end function

The VM handles such user function parameters and return values like local variables. So their life-time is limited to the scope of the function call.

Both user function arguments and user function return values do support optional default values and optional standard measuring units:

function myFn($a, $b := ??default-value??, $c := ??default-value??) -> $res := ??default-value?? { ... } end function

For instance:

function myFn($foo, $bar := 10, $bla := $someGlobalVar) { 1st argument ($foo) is required to be passed by caller(s), whereas 2nd and 3rd arguments ($bar and $bla) are optional } end function

You may even provide a default value for results like:

function myFn() -> $res := call anotherUserFn() { $res is initialized with value returned by anotherUserFn() call } end function

So as in other programming languages, user functions can be declared with optional parameters that may been passed by specific values (or variables) by callers or omitted. If omitted, then the respective function parameter is automatically inititalized with its defined default value.

Unlike many other programming languages, NKSP provides support for standard measuring units as a core language feature. So you can now also define user function arguments and return to be of a specific unit type like Hz for frequencies or dB for loudness, etc., which provides a more intuitive approach to variables and prevents many programming errors already on language level:

function calcFrequency(~freq := 0.0Hz) -> ~resFreq := 0.0Hz ~resFreq := ~freq + 20.0Hz end function

Declaration of global Variables at global Scope

Global NKSP variables may now also be declared at global scope. Previously variables could only be declared exclusively within the body of an event handler or user function. The latter makes sense for local variables of course, but for global variables this always looked a bit odd compared to other programming languages. So the following new style:

declare $someGlobalVar := 200 on init { ... } end on

is identical to the following old style:

on init declare $someGlobalVar := 200 { ... } end on

Backward compatibility is preserved though, so global variables can still be declared within the scope of event handlers and user functions and there are no plans to remove that possibility for long-term compatibility reasons.

Separate Name Spaces local vs. global Variables

As with most programming languages, local variables use their own variable name space. That means you can define a global variable and a local variable with the exact same variable name. The local variable has always precedence before global variables, e.g.:

{ global variable $foo } declare $foo := 1 on note { local variable $foo } declare local $foo := 2 { this will print "2"} message($foo) end on on init { this will print "1"} message($foo) end on

Strict Variable Assignments

The NKSP language is now more strict regarding initialization of variables. previously it was possible to assign a value with different data type to a variable, which just caused a parser warning. Now the parser requires the assigned value type to match the variable type and would cause a parser error otherwise.

on init { OK: assignment of same data type (both integer) } declare $foo := 2 { WRONG: assignment of real number data type to integer variable } { declare $bar := 2.1 } end on

This strictness was required due to grown complexity of the NKSP language.

Strict Array Size

The NKSP language is also more strict on declaration of array variables. So far it was possible to declare exotic array variables of size zero. This is no longer allowed and results in a parser error now instead of a parser warning as before.

on init { OK: declaration of positive array size } declare %foo[10] { WRONG: array size must be at least 1 } { declare %bar[0] } end on

New Build Requirements

The following changes have been made for building LinuxSampler.

Flex / Bison required

In this release we are no longer shipping pregenerated parsers with the release tarball. Instead LinuxSampler now has a strict build dependency for Flex and Bison to auto generate the parsers from the source language files. Some of you had issues with generating those files with Flex and Bison. These issues have been addressed in this release as well, and there is no longer a need to manually call scripts to regenerate parser files, they are now automatically regenerated on source file changes by "make".

Support for Lex / Yacc dropped

Support for ancient lex and yacc has been dropped in this release, so the sampler can only be built with Flex and Bison only. Effectively we already Flex/Bison-only features for a long time, which were not supported by ancient lex/yacc. In other words: the sampler could actually not be built with lex/yacc already for a very long time, so we are just making this more clear now with specific configure check and error message instead of cryptic compiler errors. In practice the original lex/yacc were barely seen installed on systems for decades anyway, for good reasons.

Test Cases

LinuxSampler's test cases can now be conveniently compiled and run with a simple make check command. Test coverage has also been extended.

Many Fixes

A bunch of other issues have been fixed as well. As always, please refer to the LinuxSampler ChangeLog file for more details.

Gigedit 1.2.2

This is merely a maintenance release of Gigedit, with several fixes and some updates to libgig's latest C++ API. Refer to Gigedit's ChangeLog for more details.

libgig 4.5.0

Our fundamental file access C++ library libgig has received few new features and a bunch of fixes, some of them fixing major issues like undefined behaviour or hangups. Therefore it is recommended for all users to update to this version of libgig.

New libgig methods

Few new convenient methods have been added, namely DLS::File::CountSamples(), RIFF::File::totalDataChunkCount(), RIFF::File::totalListChunkCount() and RIFF::File::totalChunkCount().

Improvements to Progress Notification

Progress notification (callback) mechanism has been improved in this release to reflect more accurately the current progress on long taking operations like opening or saving files.

Additionally applications can now also show the specific detailed action (e.g. as text on a progress bar) libgig is currently performing to provide the user a more in-depth feedback on what's going on exactly, especially when saving files larger than 10 GB, which can take several minutes to complete. To accomplish this, applications may access the new struct field RIFF::progress_t::action to obtain the current action as a string.

Test Cases

libgig's test cases have seen an overhaul in this release. The dependency to the cppunit library has been dropped and all tests can now simply be compiled and run via a simple make check command. That lowers the barrier for users and developers to check libgig for correct behaviour on their system. Test coverage of libgig components has also been extended in this release.

const-ness

A bunch of libgig methods have been const-ified like Exception::PrintMessage() and RIFF::progress_t::subdivide(), to allow them being called from const C++ methods by applications without any const_cast hacks, which would have otherwise caused compiler errors before.

Gig Tools

The command line tools coming with libgig have finally been updated to libgig's latest API which pacifies a bunch of compiler deprecation warnings.

Fixes

And last but not least there have been several fixes for libgig. Please refer to libgig's ChangeLog file for more details.