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.
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.
The NKSP real-time instrument script language was extended with major new features on language level:
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.
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
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.
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
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.
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
The following changes have been made for building LinuxSampler.
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 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.
LinuxSampler's test cases can now be conveniently compiled and run with a
simple make check
command. Test coverage has also
been extended.
A bunch of other issues have been fixed as well. As always, please refer to the LinuxSampler ChangeLog file for more details.
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.
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.
Few new convenient methods have been added, namely
DLS::File::CountSamples()
,
RIFF::File::totalDataChunkCount()
,
RIFF::File::totalListChunkCount()
and
RIFF::File::totalChunkCount()
.
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.
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.
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.
The command line tools coming with libgig have finally been updated to libgig's latest API which pacifies a bunch of compiler deprecation warnings.
And last but not least there have been several fixes for libgig. Please refer to libgig's ChangeLog file for more details.