I'm planning on having little detached wires hanging off of the outputs to hint at their polarity when they're disconnected. When they're connected my intention is to have an arrow indicating the directionality of the connection.
Also I'm annoyed that math words are all verbose. "term" and "sum" fit as alternatives for the inputs and outputs of the add node, but the vibes are off. "result" reads better than "sum" for the output. I don't like "term" because it's ambiguous. "summand" is too long. "addend" both is too long and it looks like it says "add end" which what. In the end I went with "+" for the operand end of the tile and "=" for the result end. (operand is also too long)
"input" and "output" could work, but I'm intentionally avoiding them so the output tile doesn't have an input named "output"
idk what I'm going to do for the "min" and "max" tiles lol
also I'm considering making the add tile effectively just a pass through and having the system add all wires connecting to the same input when the input doesn't have a special arithmetic meaning. eg draw two wires to the line out and it just adds them. or draw two hz values into a sine wave and it adds them. draw two values into a mul tile and it multiplies them instead.

The connect mode is fully functional now, and because I felt it added too much overhead, I also added a magic auto-connect/disconnect function to the selection mode since most pairs of tiles will have one obvious implicit connection anyway.

Here's a video demonstrating both:

I figured maybe I'd have a go at porting over my synth pipeline tonight, but I also decided I wanted to rebuild it as a python C++ extension and then my attention span bounced violently off the python packaging documentation, soooo... I made the lines look more arrow-dynamic instead :3
Big progress today! I rewrote a bunch of stuff and now the program has exactly the same functionality as it did yesterday, except that some of it is written in C++ now instead of python 😎
Now the tile objects are C++ classes that python thinks are python classes, instead of just being python classes. This will allow me to rebuild the C++ audio synthesis pipeline to use the tile graph directly instead of my earlier interpreter, and the tile graph will be constructed and manipulated by python.
and I wont have to worry about keeping two separate graph representations in sync, they'll just be the same graph.
I made a compiler for my visual synthesizer language thingy today

The next main things to do are building out an audio subsystem for the program so you can hear the patch, and then there's some important stuff missing from the editor like being able to place new tiles.

One of the things I'm really excited about with the design of the compiler is if you modify a patch while it is running, the oscillators don't reset, so you should be able to make a program while performing it :3

I got the audio hooked up to it and everything seems to work right :3
I am now the operator, with my virtual calculator.
the screen shot doesn't show off how cool this is, because when you're using this to edit constants in the patch, it'll update their values as you input expressions (so, every time you press equals or input a second operator) and so you can hear the change to the patch as you are doing math
I don't feel like being mad at linux right now, so I'm gonna figure out how to record this another time
I've got this hooked up to my audio convolver (a simple slow morphing fm patch convolved with the sound of a metal water bottle with a little bit of water in it being perturbed) and it sounds mesmerizing. Mym described it as "birds in a pinball machine" :3
I've been listening to it for like an hour and I'm so zoned out now 😎
I made it so you can rearrange the nodes now :)

I added a way to actually place tiles now instead of hard coding them!

finally, after five weeks and change of building a visual programming language from scratch, i can now build a working patch starting from nothing :D

The natural thing to implement next would be save and load, but pygame doesn't provide anything for conjuring the system file io dialogue windows (SDL3 has it, but pygame is SDL2 under the hood iirc). I'll worry about that another time I guess.

I'm probably going to go with an xml format so it's easy to extend. I want it to be easy to make custom controls in other applications eg game engines, so this feels like the obvious choice also I'm one of the five people who likes xml.

i'll probably end up adding envelope generators and midi before i implement save and load since it's not really worth using without those but it really depends on which way the wind is blowing when i next work on this
I'm really excited because all of the hard stuff is done now. I mean none of it was hard to implement or design, it's just that I made a bunch of architectural decisions up front and five weeks later the result is a thing that 1) works, 2) I've managed to keep the complexity of implementation pretty low across the entire program, and 3) all of the missing features and areas I want to improve upon have obvious paths to implementation.
and so further effort put into developing this will have an extremely favorable ration of time spent actually making the program more useful vs wallowing in tech debt
I made a short sequence of boops entirely out of oscillators and arithmetic. There's no sequencer or envelope generator. #mollytime
and this is the patch, or at least here is most of the patch. it probably looks complicated but I did not put a lot of thought into it
from my experimentation so far since I got all this working end-to-end, I think modality worked as useful convenience for standing up a visual programming language quickly, but it adds too much friction to this one. In particular when making patches I want to be able to alternate between placing/moving stuff around and connecting stuff, so those two modes need to be merged for sure.
I'm not really making good use of multitouch because I've been developing this using a mouse. I'd like to have it so I can touch two things to hear what they sound like connected or disconnected; and then double tap to connect or disconnect that connection when a quick connection is possible. Mouse mode will need to work differently.
Another verb I would like to implement is the ability to disconnect a wire and connect a new wire in the same frame. The current flow for disconnecting a wire and connecting a new wire is too long even with a touch screen, but I think anything where it is not one action would be.
Being able to suspend/resume updating the patch that is playing while making edits is also a thing I want to implement for similar reasons, but I think being able to splice parts quickly is useful in different ways.
I added a flip/flop instruction. It's mostly a toy, but it's helped me clarify how I want to handle envelopes.
here's what that patch sounds like
I'm sorry everyone but I have to confess to a sin. See that chain of flip flops up there two posts ago? That's a number. That's a number where every bit is a double precision float 😎
I came up with a pretty good approximation of a dial tone on accident while implementing a mixing node. #mollytime
and here's the patch for that sound
Also now that I have tile types with multiple inputs and/or multiple outputs, I went and cleaned up manual connect mode to make it a little more clear what's going on.
today I added an envelope generator and some basic midi functionality. and then I made this absolute dog shit patch :3 #mollytime
it'll be a bit of work to do, but I want to eventually add a convolution verb to my synthesizer so I don't have to run it as a separate program. I'll probably also end up rewriting it to be a FFT because it would be nice to be able to have longer samples and maybe run several convolutions simultaneously. That might be "get a better computer" territory though.
I had this really great ambinet patch going where it was these washes of noise convolved with a short clip from the chrono cross chronopolis bgm, and I recorded 3 minutes of it but audacity just totally mangled it. There's this part that sounded like a storm rumbling in the distance but it was just the patch clipping, and that seems to be the danger zone for recording and playback I guess.
so you're just going to have to pretend you're hovering gently in a vast warm expanse of sky and ocean with no obvious notion of down, as a storm roils off in the distance, during an endless sunset. the moment is fleeting, yet lasts forever
saving and loading is probably going to be the next highest priority feature now. you can do a lot with simple patches, but it would be nice to be able to save the more interesting ones
I've got saving and loading patches working 😎 that was easy
I've been very careful so far to make it impossible to construct an invalid program, but I'm eventually going to add a reciprocal instruction (1/x), and was pondering what to do about the (1/0) case and I had a great idea which is instead of emitting infinity or crashing, what if it just started playing a sound sample as an easter egg. I'd have to add another register to the instruction to track the progress through the sample though.
I haven't picked out a good sample yet for the (1/0) case. A farting sound is too obvious and puerile. The most hilarious idea would be to start playing a Beatles song on the theory that if you messed up the copyright autotrolls would kill your stream, but I don't want the RIAA coming after my ass.
I might just have the rcp component explode if you feed it a zero.
ok it's less sensational than stuffing an easter egg in here, but I realized I can simply have it refuse to tell you the answer if you try to divide by zero
I'm thinking of adding a tile type that could be used to construct sequences. It would take an input for its reset value, a clock input, and an input for its update value. It outputs the reset value until the clock goes from low to high, at which point it copies the current update value to its output. This would let you build stuff like repeating note sequences with two tiles per note + a shared clock source, and you could use flipflops to switch out sections.
I made a crappy oscilloscope for debugging. Every frame it draws a new line for the magnitude of the sample corresponding to that frame. This does not show the wave form accurately because it's just whatever the main thread happens to get when it polls for the latest sample. This is mostly meant to help check the magnitude to verify that it matches expectations. A red line indicates clipping happened. #mollytime
And here's what an eccentric patch looks like in scope view. I'm using the RNG node as if it were an oscillator, but I didn't try to correct the range, so the samples are all positive. Also it clips like crazy. Anyways here's 3 minutes and 29 seconds of hard static to relax and study to. #mollytime
personally, I highly recommend the 3 minutes and 29 seconds of hard static
I reworked the oscilloscope so that it now shows the range of samples in the time frame between refreshes. Here's a short video fo me playing around with inaudible low frequency oscillators. Also, I added a "scope" tile which you can use to snoop on specific tile outputs in place of the final output. I'm planing on eventually having it show the output over the regular background when connected so you don't have to switch modes to see it.

The scope line is sometimes a bit chonky because it's time synced, and recording causes it to lag a bit. It generally looks a bit better than in the video normally.

You can also make it worse by taking successive screenshots :3

mym tells me this is ghost house music #mollytime
and here's most of that patch
one of the things I think is neat about programming is the way fundamental design decisions of the programming languages you use inevitably express themselves in the software you write. for javasscript it's NaN poisoning bugs. for c++, it's "bonus data". unreal blueprints have excessive horizontal scrolling on a good day. blender geometry nodes evolve into beautiful deep sea creatures. as I've experimented with mollytime, I've noticed it has a wonderful tendency to summon friendly demons
I have all these big plans for using procgen to do wire management ( https://mastodon.gamedev.place/@aeva/114617952229916105 ) that I still intend on implementing eventually, but I'm finding their absence unexpectedly charming at the moment
aeva (@[email protected])

Attached: 1 image I put it to the test by translating my test patch from my python fronted to a hypothetical equivalent node based representation without regard for wire placement and then stepped through my wire placement rules by hand. I'm very pleased with the results, it's a lot clearer to me what it does than the python version is at a glance.

Gamedev Mastodon
anyone up for some doof and boop music #mollytime
a good test to see if your speakers can emit 55 hz or not
I whipped up a version of the doof-and-boop patch that automates the alternating connections with a pile of flip flops and I've been grooving out to it for the last two hours 😎
I tried doing a live jam for some friends tonight where I had the drum machine patch going along with a simple synth voice on top of that which I intended to drive with the midi touch screen keyboard I made back in January, but I quickly found that to be unplayable due to latency in the system. I'm not sure exactly where as I haven't attempted to measure yet.

I figure if I move the touch screen keyboard into the synth and cut out the trip through the midi subsystem that might make the situation a little better (again, depending on where the real problem is)

Anyways, it got me thinking, I think processing input events synchronously with rendering might be a mistake, and it would be better if I could process input events on the thread where I'm generating the audio.

@aeva Badoofboop could be a good name for ur whole app.
@dbat I named it mollytime :)
@aeva ok what about hotkeys for the side buttons? or do you just perfer using the buttons?
@cxxvii its designed for a touch screen monitor, which I have, but it's an external monitor that I usually don't bother to go get first
@cxxvii I'm planning on making control schemes for game controllers as well as mouse+keyboard eventually, but I want to nail down the core functionality first before I do that
@aeva this is a lot
@efi it's not as bad as it looks XD
@aeva but I have tiny brain
@efi its ok. store bought brains are valid too. maybe.
@aeva I have to go buy more?? bwuuuuuuh =w=
@aeva How can I tell if the fude i have is loud or not?
@EndlessMason if you have a bass note and a treble note play at the same amplitude, the bass note will sound really quiet because human perception reasons, so to fix that, you drop in the loud fudge instruction to amplify or diminish the amplitude based on the note's expected frequency
@aeva Oh, i see, so it fudges the loudness, rather than being a fudge that is loud
@aeva it feels like something out of an extremely average platforming game from 1997
@aeva that's way less than the 65 days I have grown accustomed to!
@aeva I hope you don't mind me chiming in and saying that I think this is incredibly cool. I am currently super fixated on learning more about sound design and generative music.

@aeva I've started having ngscopeclient filters output a quiet NaN when they have a scalar output and are requested to do something that doesn't make sense (missing inputs, contradictory configuration, divide by zero, etc).

(For waveform outputs we already had the ability to simply not output anything, but there's no concept of a null scalar in our object model)

@azonenberg I don't want to have NaNs either. If you pass in a zero, this will just not update the output register and so the output register will retain whatever value it had the last time the thunk was called with a valid input, or contain a zero if it was never called with a valid input

@aeva It depends on if that's the goal.

I want to avoid having stale output that the user thinks is a valid measurement and uses in some way, but the filter is actually just not updating because some config is bad or you disconnected the input or whatever.

Putting out a NaN makes it very obvious "you're not getting good data"

@azonenberg yeah, i wouldn't recommend my solution for your project. My goal is to never have NaN poisoning bugs and not introduce exceptions into patches. I figure not updating the value is a good default because it's not unusual to have code that hovers around approaching zero in a divisor that isn't technically supposed to stick the landing but does anyway. also it would be safe to do something wacky like plug a sine wave into it and clamp the output
@azonenberg (not that there's any need to since there's a square wave intrinsic, but still)

@aeva if you want to have sensible behaviour, could always make it zero, so that you can easily do idk, inverse of a notch filter or whatever

also, obviously the correct sample is strong bad the system is down

@aeva I think it's the second time you mentioned saving and last time you mentioned native file browse control but if you force all patch to be in a single directory (let's say %appdata%/your_app or ~/.config/your_app), you could simply have a button called save and another called load which clear the area and display a button per saved patch
@gkrnours I was considering doing something like that but I also don't want to bother implementing text input just yet
@gkrnours I'm going to give tkinter.filedialog a try though
@aeva you could simply name them with the f"{date.today().{patch_count_for_that_day + 1}". Should do the trick for a first version