SOUL Lang


#1

You crazy bastards - you developed audio shaders! Congrats and sounds like you had a boat load of fun developing it!

Looking forward to seeing it working outside of the presentation. :slight_smile:


#2

https://soul-lang.org/


#3

@jules did it again, he blew the mind of everybody during his keynote :joy:


#4

As a newcomer to pro audio programing, this was pretty intriguing and on a fundamental level makes sense.


#5

Shadertoy was mentioned briefly, it’s my favourite site. It’s all Java script.
GPU sound was available years ago, but it fills buffers with the GPU for later playback in WebGL. GPU audio examples:
https://www.shadertoy.com/view/ldfSW2
&
https://www.shadertoy.com/view/4tl3RM :grin:


#6

I’m in with SOUL once I am convinced it allows doing a granular synth/sampler without too much headache. :wink: (I am a bit worried that access to external audio file resources is going to work well only with forward in time streaming only, I’d need full random access…)


#7

I felt like the earth shook underneath. You guys rock, cant wait to get my hands on this


#8

Hehe, Jules finally (re)discovering Domain Specific Languages for audio and music… :grinning:

Some of them, older and more recent (Antescofo, Csound, Gen~, Faust, Kronos…) are presented at PAW (http://faust.grame.fr/paw/).

Some of them (Faust, Kronos…) have been using the LLVM IR/JIT compilation chain fo ages… Some of them (Faust, Kronos, Csound…) also use WebAssembly for dynamical compilation on the Web.

Some of them (Faust, Kronos…) have been doing auto-vectorization. Some of them (Faust…) have been doing auto-parallelization.

Interesting discussions to happen at PAW for sure…:wink:


#9

And don’t forget Chuck, with its so smart syntax !
I love the “hello sin” program:

SinOsc s => dac;
2::second => now;

:sunglasses:


#10

I think what would be great, would be to have something similar to the Java ecosystem in terms of a common bytecode layer, and different languages such as SOUL, Faust etc that can compile to it.

For me the really interesting part is being able to bypass typical OS constraints and run audio code at the kernel level, or even on external DSP chips.


#11

I guess running JIT compiled code in kernel mode causes some security issues… Then the reason for this SOUL secure IR. For Faust interacting with the SOUL platform can probably be done first at “source” level, that is adding a Faust => SOUL backend in the Faust compiler to generate SOUL code. We’ll see if JUCE people then choose to open the SOUL IR format at some point (assuming it makes sense ?) to generate code at a lower level.


#12

@adamski - yes, that’s exactly what we’re doing!

And yes, we’ll certainly open up the IR format so that other front-ends can generate it, that’s all part of the plan! Everything in front of that layer (i.e. the SOUL->IR compiler and other API code) will be completely open.

Hopefully there’ll one day be many different drivers to run it (some open and some closed-source) but creating code for them to run is something we want to encourage everyone to do.

(Although I think SOUL is going to be by far the nicest front-end language to use… :slight_smile: )


#13

So this is the reason to have the Faust => SOUL first :wink:, to generate tons of lines of beautiful SOUL source code in one click…:sweat_smile:


#14

Sorry to change the topic a little here but this quote reminded me of my initial thought of seeing the SOUL code in Jules’ talk… If SOUL is designed to be a nice, clean, easy to use, coder friendly scripting language (maybe that’s not what SOUL is meant to be, in which case please do tell me to shut up!) then why does it use C-like syntax?

“Only an idiot would write a new C-like language…”

I personally see a great oppotunity here to have a language with more of a Python-like syntax -
nice and clean, and more human readable.

processor HelloWorldBeep
{
    output beepOutput: stream float;

    void process()
    {
        float phase = 0;
        
        for(int i = 0; i < 30000; ++i)
        {
            beepOutput << sin(phase);
            phase += 440.0 * twoPi * processor.period;
            advance();
        }
    }
}

Just in this first small example Jules gave I see several things that I feel could have been done in a much nicer, non-C way.

First of all - why not make it dynamically typed? That way if you want to change between single and double precision you don’t need to go through and change hundreds of bits of code, it can just be an option somewhere higher up.
Second, why the old cumbersome for-loop style? Pretty much every bit of audio code contains at least a few for-loops - why not make them a bit prettier: for i in range(30000)?
Personally I’d also say get rid of the braces in favour of indented blocks but that’s just personal preference over any technical reasons (and because I’m a Python nerd)!

processor HelloWorldBeep:
    output beepOutput: stream

    def process():
        phase = 0
        
        for i in range(30000):
            beepOutput << sin(phase)
            phase += 440 * twoPi * processor.period
            advance()

Not going to pretend I’m an expert in this - if there are many solid arguments against my ideas I’m happy to hear them, I just feel this is a missed oppotunity to make a super clean, modern language that’s easy for anyone to learn instead of yet another C language!


#15

It’s not a scripting language. It’s a performance-oriented realtime language, designed to run on heterogenous architectures, and very much focused on being close to the metal.

As far as aesthetic choices go, the priority was to make it completely familiar and easy to learn for our target audience. And that audience is going to be C/C++ audio programmers, people writing apps (i.e. almost entirely Java, Javascript, C#, C++ and Swift). And electronic and embedded engineers (almost all C/C++). All those languages use brace syntax. We’ll have Python bindings, but I expect only a minority of our users to be people for whom python is their main language.

We will add some syntactic sugar for range-based for loops and various other things, but maybe not until V2. The V1 of a language should always be ultra-conservative in its scope so that when people are writing it and we learn more about common use-cases, we don’t regret any early decisions.


#16

BTW, the code you quoted there was edited for showing on a slide - here’s an example of a real program to do that beep:

// Plays a brief sinewave, and stops
processor Beep
{
    output out: stream float;

    void process()
    {
        let beepFrequency  = 440.0;
        let phaseIncrement = float (beepFrequency * twoPi * processor.period);
        float phase = 0;

        loop (20000) // let's render this many samples
        {
            out << 0.1f * sin (phase);
            phase = soul::addModulo2Pi (phase, phaseIncrement);
            advance();
       }
    }
}

#17

I like that it looks like SOUL didn’t jump on the functional programming bandwagon. At least the body of the process() function just does good old procedural looping and state changing. Nasty as those are, it’s just the natural mental model for most programmers.


#18

It’s also worth noting that there’ll almost certainly be people who create other front-end languages for SOUL or its IR layer. So if you really don’t like braces, or if you like pure functional paradigms, then there should be some options.


#19

Although I kind of agree, I personally think the syntax looks good, somewhere between C and Swift.


#20

Me too :slight_smile:

Talking to the AudioKit guys, they said it looked odd to see so many semi-colons, as Swift programmers have got used to not using them very much… That’s the kind of syntactic sugar we can add later, but are focused on keeping it simple for V1.