Syntə RSS repo @m
bandcamp
say hi! events
back

21/08/2026

Scope

I’ve wanted an oscilloscope for Syntə for a long time. Sometimes it’s hard to tell what is going on, like you’re trying to create a new shape and it’s not working as expected. I had a brief look for something that could do this but didn’t turn up anything that looked like it would work.
I’m not sure what inspired this exactly, but I decided to make a ‘scope that would show direct values from the sound engine. I wanted it to look nice and a bit retro so needed some blur (beam focus) and trails (beam persist) just like an old-skool CRT one.
I’d also been meaning to try some shaders for a long time too, having seen others do cool stuff. Maybe there are other ways of doing it, but they seemed like they would do the trick.

Shaders seem really hard, and they are, but not exactly in ways I expected…

first steps

I wrote out a list of details first to get an idea of how this would work.
I’m already using SDL2 as an audio compatibility layer, so it made sense to use that to open a window to run the scope in.
Here was the first hurdle:
SDL like a C++ diva wants to hog the ‘main thread’ - which means it wants you dedicate all your attention to feeding and nurturing it. This ain’t gonna happen.
Syntə is dedicated to producing audio, I’m not going to contort myself into weird shapes to please a graphics library. Plus I wanted the scope to be optional, you don’t have to use it and you don’t even need the dependencies installed.
So that meant I had to run the scope as a separate program. Which turned out to be fairly straightforward.
It goes something like this:

acting shady

this is where things get quite bleak…
The main pain of shaders is a whole deluge of boilerplate! you need - a window library (SDL) plus an opengl library (go-gl in this case), then you need to initialise each, create contexts, generate arrays, buffers, bind things, compile vertexes, fragments, aargh it is a LOT.
bcos i am lazy I used some example code and hacked away at it until I got something working.
This resulted in a display of points rendered in a natty green colour that showed waves moving about - success!

but no blur and no beam persist… sad face

this was probably the hardest part - I realised that I needed a second shader and somehow smoosh it together with the first one.
After spending ages reading stuff on the internet it also slowly dawned on me that opengl is pretty ’legacy’ these days. yikes :/
the modern way seems to be webgl, and there is a go library for that but it looked pretty vibe-coded. meh.
talking of which lol

enter the villain

around this time my mate said he would vibe code the scope on his laptop in the pub haha. I point blank refused to hand over what I had already but for the sake of curiosity verbally suggested a ‘prompt’ to see what it would do.
the result looked like a lot of the example code I’d seen already, which of course is what it is. a whole lot of scraped content slurped up and mashed into a blob.
I did in the end run the code to see what it would do. it worked after a bit of tweaking, but hadn’t really ‘read the brief’. It had things I didn’t need or want and didn’t have any of the hard part of smooshing two shaders together.
I understand the temptation to use an llm for this when you’re in unfamiliar territory and just want to get it done, but really it would have ruined all the fun+pain lol.
in the end out of laziness I based the blur and persist functions on the llm code, treating it like the other example code, which is what it was. Although I could have and id find many other examples that did the same thing in different ways.

breakthrough

the nifty technique I employed for getting two shaders to work together was moving lines of boilerplate around in every possible permutation until stuff started to work.

did i mention the vertex array objects? and the vertex buffer objects? and theres even element buffer object/arrays too if you want…
then if you want to control different parameters there are ‘uniforms’, which are not something you wear to impress authority figures lol

the end

in the end it started working and I could have fun poking at things and seeing what broke.
I added a lissajous mode which is very fun and also realised that if I generate signals specifically for the scope I can also be a rudimentary visualist! wahey!
Instead of deciding what colour it should be I made it pseudo randomly rotate hue and added something to adjust the speed.

heres what it looked like:
link to masto post
Yay!
here you can see lissajous and ’northern lights’ modes active. the latter gently shrinks each layer of beam persist to give a zooming effect that is quite hypnotic :)

so there you go, I now have a very useful tool and also am a scrappy visualist too hehe!

throwing shade

if you’re interested in shaders there are options. If you want to explore the exciting maths without all the boilerplate there are things like shadertoy.
if you want to use shaders in a more sane way you’re prob better off with webgl
if you just want to do shadery things theres hydra and voxelchant and many other options like screamer and picodevil
for everything else, theres the hellish tech stack that I ended up with lol

↑ top