Some observations

As a 30+years developer (C++, C#, Java, Python) I became increasingly frustrated with SC. At first glance the system seemed to be incredibly powerful, but gradually I realized that the language is nice, but the implementation of the engine is limited. You can’t use simple arguments in synthDefs, so you can’t write synths that play a certain sample from an array of samples, as an example. More advanced structures like Tasks and Routines are only useful at compile time (you can’t have a synth that uses a routine or task more than once) , and they lack documentation.
In SC you don’t have to declare the type of a variable. This is just being lazy. It ensures confusion and makes debugging much more difficult.
And why is it so hard to just type ‘return’ to denote the return value of a function?

Overall I think SC is the product of a developer who likes to make things easy for himself, but in effect makes things less easy for anyone who uses his product.

With all its limitations I think SC can be fun.
Once you understand that synths are simply generators and lack any logical skills, and that all the logic and conditional processing has to be done in the SC language, you can have a great time.

1 Like

SynthDefs cant take all arguments but Functions can. Have you played with the {}.play syntax?

One approach is to make functions which create “on-the-fly” synthdefs

~playSampleFromArray={ | arrayOfSamples | 
var buf = Buffer.cueSoundFile(s,arrayOfSamples.choose,0,1); 
{ DiskIn.ar(1,buf)}.play;
};

~playSampleFromArray.("myCoolSampleFolder/*".pathMatch)

Hey @Cjw! Thanks for your feedback. SuperCollider is actually written and maintained by a team of developers around the world, and not one man. If you’d like to help to improve SC, the issue tracker and code are hosted on GitHub here: GitHub - supercollider/supercollider: An audio server, programming language, and IDE for sound synthesis and algorithmic composition..

2 Likes

Most of your points about the engine stem from the need to avoid time-unbounded operations in the audio thread. See Ross Bencina’s excellent summary.

Pure Data integrates the control and audio layers, and when you add heavy objects to a patch, the audio glitches out. You really don’t want that onstage.

As for the language design – with plenty of other language clients (e.g. ScalaCollider), you don’t actually have to use sclang at all.

I’m curious what sort of facts you would use to justify a statement like this. How do you know James McCartney’s motivations?

hjh

Blockquote
You can’t use simple arguments in synthDefs, so you can’t write synths that play a certain sample from an array of samples, as an example.

I probably misunderstand your requirement, but if you load each sample in a different buffer (e.g. in an array of buffers), you can pass the buffer number of the sample you want to play to the synth as argument.

More advanced structures like Tasks and Routines are only useful at compile time (you can’t have a synth that uses a routine or task more than once) , and they lack documentation.

Synths don’t use routines or tasks but tasks can set arguments in multiple synths if the synths keep on running. E.g. I recently have used tasks quite extensively to modulate synth parameters 10 times per second based on inputs from light sensors (while other things were happening in parallel). Switching “on/off” a synth from a looping task can be emulated by setting some overall amplitude to 1 or 0 (with some lag added to it to have it fade in/fade out if desired). Using Tdef you can replace one task with another task at run-time.

Not using “return” to denote the value of a function is more or less standard practice in functional programming languages. It’s perhaps mostly a matter of what background one comes from?

SCLang for sure has quirks and a steep learning curve, but I think it imposes less limitations than might appear at first (and second) sight. So far I have not encountered any requirement in my own programs that I found impossible to realize because of limitations of the system. But there have been times where I had to rethink the architecture of my program to realize some things within the constraints the system imposes. In the end, it almost always led to a better program.

Thinking a bit more about this topic –

Actually, you’re not the first SC user to note weaknesses in the language design. A number of people have gone ahead from this to create clients in other languages.

TBH I think there’s a strong argument to be made that a future “SuperCollider 4.x” version could/should be based on a different language. One reason here is: There are some specific bugs in the SC interpreter that would be very tricky to fix. Error handling is the main one that comes to mind – that try in certain contexts unwinds the stack incorrectly and corrupts function results. We could spend a lot of developer hours trying to fix SC error handling – or, a future version could be based on a language where error handling already just works.

There may be performance benefits as well. Also, perhaps an interactive debugger etc. etc… many long-term feature requests that are probably not going to get done in SC 3.x but which could potentially come “for free” with a different language.

“In SC you don’t have to declare the type of a variable. This is just being lazy.” <<-- Careful here… sclang is conceptually based on SmallTalk. Granted, SmallTalk is a bit far back in the rearview now, and there are criticisms to be made – but at least be aware that you’re not just picking on an obscure domain-specific language here.

Engine:

The typical limitation that people bump into is that the SynthDef graph can’t adapt to the value of a synth input (e.g., expand or contract the number of channels).

How would that work?

We can’t/won’t put the graph builder and optimizer into the audio thread. That’s a nonstarter. Glitch-free synth onset is one of the major strengths of SC; we aren’t going to break that.

The best I could imagine is – we already send s_new commands some milliseconds ahead of the time when we want to hear the sound. It’s conceivably possible to use the latency gap to have the server rewire and re-optimize the graph, in a below-realtime-priority thread – have the “new” graph ready to go before the timestamp moment. But, some challenges: 1. Graph building/optimizing depends on knowledge that’s in the language class library. Duplicating this in the server would be redundant and create maintenance headaches. (It’s not safe to say that every user in every case would benefit from dynamic SynthDef graphs – so, removing the language-side builder would be a bad solution to the redundancy.) 2. These are not time-bounded operations. If you need lower messaging latency for some application, and complex SynthDefs, the risk of late synths would go up dramatically. It’s not guaranteed to be transparent.

I’d also second Brian’s comment – suggestions for improvement are more than welcome, in the github repository.

hjh

Well, this applies to all dynamically typed languages, including Python (which you’ve worked with).

However, I can certainly see why sclang might put you off, because I don’t really like it, either. But as others have pointed out, you can use another client. In fact, there are several Python clients: GitHub - josiah-wolf-oberholtzer/supriya: A Python API for SuperCollider, GitHub - ideoforms/python-supercollider: Python client for the SuperCollider audio synthesis server, https://foxdot.org/, etc.

In C++ you also don’t need to declare types of a variable. In fact, declaring an explicit type for a variable is usually an anti-pattern and should be avoided unless you’re initializing something on the stack, or explicitly declaring a type where you expect code may change in the future.

my_object a{1, 2, 3}; // stack initialization, okay
auto a = make_object(); // okay
my_object a = make_object(); // not okay!

From the perspective of sclang code, there is only one type: Object. Everything is an Object because everything can receive message sends - object.foo() is valid for every object no matter it’s type. This is mostly also true for Python, Lua, and even sort of for Objective-C (which also has runtime dispatch).

Sclang is the first programming language I’ve learned (well aside from BASIC in the 80s!) -

I often wonder whether the other language clients exist because of deficiencies in sclang or to leverage programmers’ familiarity with those languages. When I’ve taken the trouble to look its been hard to discern any advantages to someone like me who only makes music with code…

That said the “meta-language” nature of Racket looks like it could be interesting if that project ever comes together…

I do completely agree with you. I’ve got a similar background. And well, I’m more than often frustrated by SC, and thinking about quitting it (although I keep believing I’ll be at some time able to get close from the why I started with SC).
The really frustrating points to me are the heterogeneity of the syntax, the heterogeneity of behaviours with a same syntax, the difficulty of debugging SynthDefs, …
And, well, this is a community-based developed language. With, as cons, a lot of heterogeneity, a limited-roadmap and product-ownership (I couldn’t find a lot of info on this), and as benefits, plenty of new stuff, great support on the forums, …

Like I said: no explicit type declaration and the fact that it is too much trouble to type “return”.
There is a reason why C++ is still the major programming language for complex software, and SmallTalk and Python are only used in academic environments.

Explicit declaration makes the compiler/interpreter slightly more complex, but it also makes a program much clearer and easier to debug.

I agree. It is simply not a good idea to allow multiple ways to do the same time thing, simply because you want to make the interpreter as versatile as possible. Complex software needs strict rules, otherwise you will spend even more time debugging your code.

Thanks for your reply! My remark about the ‘missing’ return is related to the fact that I do not think the goal of compilers/interpreters is to make the life of a programmer easier. It should force the programmer to be as explicit as possible. 80% of the time spent on a complex program is about debugging. Typing “return” and explicitly declaring variables is a minor investment that pays off.
For the same reason it is not a good idea to allow multiple ways for doing the same thing: square(8) = 8.square. The more strict your language is, the less time you spend debugging. There is a reason why C++ is still the go to language for complex software.

I’m not sure which version of C++ you are talking about. Declaring variables is anti-pattern?

To quote JMC’s paper on SC:

“A computer music language should provide a set of abstractions that makes expressing compositional and signal processing ideas as easy and direct as possible. The kinds of ideas one wishes to express, however, can be quite different and lead to very different tools. If one is interested in realizing a score that represents a piece of music as a fixed artifact, then a traditional orchestra/score model will suffice. Motivations for the design of SuperCollider were the ability to realize sound processes that were different every time they are played, to write pieces in a way that describes a range of possibilities rather than a fixed entity, and to facilitate live improvisation by a composer/performer.”

So, the thing is, I am sure most people here agree with what you are saying about programming languages. But this is a language designed around musical structure, which is an infinite plane (look around at the music made by the people on this forum - it is not in a set genre or style), and in that it is incredibly expressive.

2 Likes

Thanks for your reply. You are right. The things I want to do with SC can be done in the language. I was merely venting my surprised frustration that the engine is not what I expected it to be. I thought I could write a complex synth with all the logic and send it to the server. The fact that I can’t doesn’t mean I think SC is useless. It just means I have to adjust.

@Cjw, I think perhaps you are looking at SC from the perspective of a software developer, and not so much as a musician/synthesist/live coder. It’s true that strict rules within a language (such as declaring variable types) are often important for developing robust, secure, and scalable software, especially in a collaborative effort. However, as someone who is primarily a musician and solo coder, I absolutely love the versatility of SC, and it’s hard to imagine the benefits of a non-dynamic language outweighing the costs within the context a live performance, for example. Maybe that’s just me and my lack of programming expertise though.

I’m not sure you want my input, because I’m an old style programmer :wink: I think that a compiler/interpreter should force you to be as explicit as possible. Explicit declarations, only one way to express things, etc. Programming is 20% writing code and 80% debugging. A compiler that forces you to write the right code is a great help in the debugging phase. Right now the SC compiler seems to say ‘hey, you can write anything you want and I still understand it’. That is just being smart, though it is not helpful.

I agree, but I also think you would benefit from a more strict language. It forces you to think about your goals more clearly. And a strict language is easier to learn because there are less (hidden) rules. And it is also much more efficient, because the interpreter wouldn’t have to convert from one type of data to another all the time. Today, this is not a problem of course. What bothers me about SC is that there are multiple ways to say the same thing: \freq: 1000 is the same as freq, 1000. This makes it harder to debug your code. \freq : 1000 is wrong, but freq , 1000 is ok. :man_shrugging:

I think this is just a difference in philosophy. I will defer to your 30+ years of experience in regards to what makes a language “good” or “bad”. However, in my experience, having a thousand different ways of doing something means having a thousand different avenues of creativity, each leading to different results. My only goal in SC is to make beautiful sounds, and having the ability to explore different ways of doing that via the flexibility of SC is a key part of my creative workflow. Again, this is just my personal philosophy and approach to using SC as a tool and certainly not the only way of judging its merits as a language.