screenshot club

I…don’t think I’ve seen it before but I might have at some point since I regularly wander around online and look at modular-synth-type programs. It looks cool!! If nothing else, I’m definitely kind of inspired by similar things, like stuff like that in Max/MSP and also like analog hardware sequencers (neither of which I actually have much firsthand experience with honestly but I’ve watched videos and read manuals and things :stuck_out_tongue: ). In general maybe most of all though I’m strongly influenced by Csound which has been a major part of how I make music for years, and that lets you pass floats and strings around and work with them as you please—it’s just not a graphical environment.

One thing that is maybe a little different about my approach…although I don’t know, maybe it’s not so different from other things despite my efforts :stuck_out_tongue: but in any case…in my codebase the ports on a module can carry data of any C++ type you want, in a way that imposes almost no intrinsic work on the module implementor. The data can be of a traditional built-in type like double or some elaborate custom message-passing type the implementor defines or anything in-between. The ports themselves are generic, and the machinery in the codebase that supports the module template even takes care of type-checking between input and output ports at connection time, keeping them efficiently type-safe without you having to do any extra work. :wink: So, it’s kind of a more programmer-friendly environment I guess, at least if you want to define your own modules, one that maybe supplies a more convenient kind of flexibility for a developer than just using MIDI or floats everywhere or that sort of thing. Conceivably if there was already a robust collection of existing modules, users who don’t code could still make things by connecting them up of course, and benefit from the fancy port stuff without having to know anything about it.

I’ve found it really fun to work in this environment so far at the very least—even in the current program I have ports that carry audio samples, digital pulses, buffer indices, and time points, and as I go on I’ll probably have some carrying graphics-rendering commands and others carrying various kinds of input events and that sort of thing. This can make for really clean and simple logic within the module definitions—the types can have whatever interface you want, and you can define conversions between them etc., so you can leave a lot of the heavy lifting to them and code the modules in a kind of high-level declarative style.

It also means that it’s easy to have sequencer commands mean anything that can be expressed with the types you have for ports to carry: if you have a type that encapsulates cannonball-launching commands for some sort of pirate cannon module, and another that can describe the production of a trombone sound to some sort of trombone synth you’ve created, you should be able to decide that entering “woooooo” and “wawawa” on a line in a certain sequencer’s score should cause both of those things to happen at once, and pretty rapidly spawn and connect the modules that will facilitate that. I don’t have types or modules quite like those two yet of course :stuck_out_tongue: but the fundamental machinery needed to do that sort of thing is there (including the sequencer module actually…I just don’t have the graphical interface to it set up yet, but a sequencer currently stores the notes for the two chords the existing program switches back-and-forth between, for example).

Also, taking some inspiration from hardware, the sequencer’s “read head,” like its idea of where the piece is in time, is exposed to the rest of the program via a duration-carrying input port, so you can either just connect it to the main clock module if you want it to work normally (note that the main clock is exposed directly in the module environment like with hardware, as a side note, there’s no “hidden global time”) or you can connect the “read head” port to something else that will move it around manually (or modulate the clock signal somehow before it reaches the port or whatever). The existing program switches back-and-forth between the two chords in the sequencer using a latch module connected to the chord sequencer’s “read head” instead of the main clock, for example, and the latch is triggered through a small digital circuit using a pulse train and delay (carrying bool for pulse, not audio, as an example of a place where the arbitrary port data types can ease programming).

One of my major goals, although perhaps it’s hard to detect in all that :stuck_out_tongue: , is actually to facilitate the sequencing of more “tactile” musical commands, more akin to what you might naturally do on an acoustic instrument, like organic and higher-level rising and falling patterns in the dynamics, fluid rubato, complex articulations, etc., in a way that you can specify from within a score as you want to express them without arbitrary limitations or needless awkwardness. (I play acoustic instruments too and I always feel a little let down by how far away the compositional language of most DAWs feels from that.) There’s a sense in which the sequencer here is almost like a little “DSL module” where you can kind of make up a miniature programming language for the other modules to respond to, with built-in support for common sorts of statements (like right now it already has a built-in text format and parser for musical pitch in 53-EDO). The contents of a sequencer’s score in this environment is more akin to a Csound or tracker score than like a piano roll or drum machine pattern or something, in that it’s like rows of text separated into columns, but its format is more up to the user than a Csound or typical tracker score. :wink: Phew okay <takes a deep breath> it’s time for me to go to sleep :sweat_smile:

2 Likes