The SOUL programming language and API
There was an issue with larger block sizes and an incorrectly sized internal buffer that caused input streams to not be connected in some situations. This has been resolved
The generated C++ requires C++17, and this is now enforced with a #error in the generated code
The tests have been moved to the tools/tests directory, and additional tests added
Adding this functionality to the patch API starts to make it possible for people to write 3rd-party code generators to cross-compile SOUL into other languages
Resolved some issues around delay processors, resolved issues around unsupported stream types and fixed some midi issues
The patch API interface was not correctly clearing down the output buffer for process calls. This is now resolved
Resolved an issue with data types for delays feeding array endpoint index, and fixed support for delays on event streams.
The documentation has been improved for the library code, now with support for SOUL syntax highlighting in library documentation.
Relaxed some rules around struct and array sizes, which are now enforced by checks for the state and stack size. Added a new --max-stack-size=<bytes>
argument to the soul command to support stack size limits.
The filter library code has better support for float32 coefficients.
Reworked the library voice allocator to support midi sustain messages, and to support MPE master channel sustain messages.
The optimisation passes have been reworked to eliminate more code earlier. This has benefits for the generated code and the computation effort.
The SOUL language is now officially at version 1.0. The language has stabilised over the last 18 months, and we feel it is now mature with a clear structure which we will be supporting long term. There are still features to add, but we do not expect the existing functionality to be affected by these enhancements.
We've been working to improve the documentation for the built-in library, and this can be found in the documentation section. We're working to include the documentation on the soul.dev website.
We've tightened up the rules around bools and ints. Previously, a bool could be implicitely cast to an int, but now an explicit cast is required. When cast, boolean false gives 0, and boolean true gives 1.
We've resolved bugs around default paramters, removed some implementation restrictions, and further work to tidy up ambiguous error messages.
The standard library now includes oscillators and filter implementations, including both sine and blep oscillators, and an LFO with various waveform options. The filters include a large array of different filters, from 'off the shelf' standard butterworth filters through more interesting filters suitable for modulation. Both building block algorithms and processors are provided, to make using these in patches simple.
We've made significant updates to module parameterisation. namespaces can now be parameterised along with graphs and processors, and namespaces can themselves be passed as specialisation parameters using the namespace
keyword. Default values for parameters can be specified using = value
syntax.
We have included a release of the SOUL command binary for OSX/ARM
There has been further improvements in eroor reporting, and resolution of issues uncovered in the public forums and internal development. Compilation performance has been improved, and the C++ generator has had some rework.
The venue API has been reworked to be asynchronous, and a wire protocol developed. This is working towards support for SOUL on remote appliances, and out of process audio execution engines.
You can now also write a static_assert directly inside a processor or namespace.
Fixed various bugs around complex support, related to derived types and structures
Updated soul command to resolve issues around failing to compile causing segfaults in the tool. This also fixes a similar problem when using the patch library.
We've been updating the library code to make it more consistent, and to extend the support. The oscillators have been updated to take advantage of namespace specialisation.
We've tidied up various error messages to make them clearer, and more descriptive.
A new FIFO system means that outgoing events (including console messages) can now be collected on a different thread to the render thread. In the JUCE plugin wrapper, they are delivered on the message thread. In the Blueprint wrapper, there are new javascript bindings to send and receive custom events, which will enable features like metering and other custom run-time communication between the DSP and the GUI.
The primitive types have been extended to include complex32
and complex64
support. There is a complex
type which like float
provides the fastest host complex data type. The complex type support normal arithmetic operators, equality comparison, and the .real
and .imag
accessors to retrieve the real and imaginary components respectively. Imaginary constants can be created using the fi
suffix for 32 bit and i
suffix for 64 bit floating point values.
Namespaces can now be parameterised, similar to the existing logic for processors and graphs. Namespaces are now valid specialisation parameters. Namespace aliases are created using the namespace keyword (e.g namespace foo = bar (float32);
)
There was a degree of ambiguity when apply numeric operators to clamp and wrap objects - should the result be of the same type as the clamp/wrap, or should it be an int? We've moved to returning an int, which will require a cast to the clamp/wrap type if that is the desired result. It makes the resulting type clearer in some situations (e.g adding two clamp types of different ranges). The assignment operators work as expected (so will automatically keep the value within the clamp/wrap range).
With this release, we've updated the logic for determining data types for generic functions. Previously, when deciding what type should be used, the rules allowed for silent casting to candidate types, which could lead to confusion (e.g. a call to max (1, 2.0)
would compile, and would return an int
value 2
whilst max (1.0, 2)
would compile and return a float64
value 2.0
). The compiler will now fail to compile such code unless the types match exactly.
Resolved various issues around vector cast operations in the llvm backend.
Various updates to the heart parser to resolve possible issues around naming conflicts.
The voice allocator now correctly forwards control events
The soul command has various fixes applied to resolve implementation errors.
We've removed the do...while construct from the SOUL language. It was unused in our example code and it felt like the loop construct covers all of the use cases without adding the extra language feature.
We've added support for specifying input/output devices, and overriding the library code path to aid with library code development efforts.
A bug had slipped into the language allowing automatic conversions between primitive types that could loose resolution (e.g. converting a float32 to an int32). This has been resolved, and may cause existing code to be modified to include cast operations where such behaviour is required.
A patch can now declare some input events to receive various timeline-related data from a host - this includes BPM, time-signature, playback position in quarter-notes and samples, and the playhead state (i.e. stopped/playing/recording).
We had some bugs around graphs containing processors writing to the console which are now resolved, and have better support for auto wiring when processors use the console
Resolved issues with event arrays - resolved problems with size 1 arrays, and fanout to event arrays.
Moved various checks out of the HEART parser into the AST classes or validation checks.
We've integrated the Blueprint React-on-JUCE library to make it possible to add Javascript-based React GUIs to patches. This is very much an experimental alpha-stage version, so feedback is welcome.
Modifications to stop accidental playing of .soul files rather than .soulpatch files. A new '--nopatch' option restores the previous functionality.
Tidied documentation.
Updates to member initialisation to use initial values, simplying requirements for system generated init functions.
Event connections now support the delay [n] syntax.
Various improvements to interfaces to make the codebase more consistent
Connections can now omit naming of endpoints if there is only one. This means that for processors with a single input and output endpoint, they can be used in a connection chain (e.g where previously you might need two connections to route via a processor, for example audioIn -> processor.audioIn, processor.audioOut -> audioOut
this can now be written audioIn -> processor -> audioOut
)
The location of public header files had ended up getting a bit cryptic, so there's now a top-level include folder which should make more sense, and users can add the top-level include
folder to their paths.
The C++ generator includes support for doubles in it's RenderContext. float is used by default, but the RenderContext is templated on the float type.
Added a roundToInt() intrinsic. Fixed problems with the implementations of ceil() and floor()
The RenderContext now always includes input and output arrays, and there's changes to the parameter class so that setValue() correctly applies min/max/step annotations, and there's an additional getValue() method to return the last setValue()
Writing to streams was previously supported, but not reading (an oversight). We've fixed this in this release, and added additional logic to ensure that such functions can only be used from valid contexts (e.g you can't read or write to streams from event handlers).
Fixed incorrect json in new patches. Resolved compiler warnings in the windows build. Additional HEART code validation.