Thought I’d start a thread of things related to Audulus 4 development, for those who are interested. Here you can get a peek into some of the coding decisions
I recently posted some code for review:
Thanks for the insight! Although it’s a very foreign language to me, it’s nice to see you open about the process!
Awesome! It’s nice to see what fellow developers are up to. How much of Audulus is written in C++?
@SynthEnthusiast The patch editor UI, and the audio engine are C++. That’s the majority fo the code. The iOS/macOS specific code is almost all Swift.
I’m getting closer to eliminating the pointers up the tree (like from nodes to their patches). Also going to eliminate storing positions and names in the inputs/outputs. This should significantly reduce the size of the data model in memory, possibly enabling snapshot-based undo/redo (which is simpler than the memento pattern I currently use), and multiple snapshots within a patch.
Right now, some of the bigger patches in the library use over 1mb just for the data model (that’s roughly what’s stored in the file, so not including DSP stuff like delay buffers, which are pretty big). If you do undo/redo with snapshots, then each snapshot would take over 1mb. If you had an editing session with 500 actions (pretty easy), then there goes half a gig of ram.
Of course I could limit undo/redo history. But perfectionism
Here’s an Apple talk about data models with value semantics, building up to doing undo/redo with snapshots. They also discuss how Photoshop uses snapshots, and shares little image blocks between snapshots, which is pretty cool.
All that said, I’m not convinced I can get the Audulus memory usage down enough to do snapshots for undo/redo. In the case of Photoshop, much of the data can be shared between snapshots. For Audulus, which is quite nested and symbolic in nature, it’s harder to do that sort of sharing (notice how in the talk, they only share things that don’t contain other things). I could share all the nodes, but then I’d have to make an exception for Modules. It could get tricky.
Same here. I’m using memento pattern on my flowchart projects and it’s a memory hog. But I’m coding for a desktop so the memory requirements are low priority.
I’ve never tried this, just an idea. Could you store the initial state in memory and then push only changesets to the undo stack? Like git commits. Then popping off the undo stack is like reverting the last changeset. Maybe the changeset is a binary difference if you are not storing the state in some kind of JSON like string. Those changesets have got to be less memory and it kind of implicitly shares as much of the source as it can.
I think that’s a pretty good idea. Audulus stores everything as JSON, which could be diffed (I see that the nlohmann JSON library will do diffing). I’ll look into that further. Thanks for suggesting it!
I have a goal of having quick random-access undo/redo, which snapshots offer, since you don’t have to apply a potentially large sequence of diffs. Plus we’d get a patch snapshotting feature for free.
I think the solution to making snapshots memory efficient may be hash-consing. I may also switch to an immutable data model, but as mentioned in that Apple talk, it can make editing operations rather cumbersome.
That “Generic Flyweighting Function” I posted above is my primitive for hash-consing anything with
Posted this over on Reddit: https://www.reddit.com/r/cpp/comments/cikmhh/implemented_sean_parents_polymorphic_value_types/
Answered this question on Quroa: https://qr.ae/TWvbY2
Please upvote if you are on there, and save people from bad implementations of undo/redo.
A peril of modern life, I’m afraid.
I can’t wait to check out the very first beta version, i wish i couldn’t understand C++ but instead can we have a hint of some of the new features ?
@Nomak there are a couple hints above
Quick update: the new code is now running some example patches
There’s a new file format which is much more compact (your existing patches are upgraded to it). It uses Flatbuffers and I will be providing a schema file for those who want to generate patches via code.
I expect to be able to make this code extremely stable. It’s a very solid foundation for the future of Audulus
Thanks for keeping that an option! Making patches via code is a super fun tool.
Thanks so much for sharing the c++ aspect of audulus, I had to start with the arduino platform and ide, then got deeper into oop (object-oriented programming) with teensy. It’s great to see someone who really knows how to use it!
It’s been a while since the last update in this thread - how is development going?
Hey @taylor! I hope all is well with you! I was just thinking, and I don’t know if this is in the road map, but I thought it might be really over the top amazing to have a sample node in A4. Maybe something that would allow you to record sounds that could be triggered by MIDI or (virtual) CV from other nodes, and then be able to shape and sculpt the sounds with the other amazing components of Audulus that already exist.
I am not sure if this is something that would be easy to implement, if it is not in the roadmap, but I did want to put the suggestion out there, as I think a lot of users would really like this capability to be a possibility in their modules. Anyway, whatever you decide, I am sure it will be awesome, and I know I will be for sure making the purchase the first day it is available!
Update: we’re designing a new collection of core modules. Things are looking great!
I fully agree. In the meantime I highly recommend using the delay module with the loop time sync module from the reface library. I just started to work with that and I think if you have a nice time synced patch and you want to grab loops and alter them there is a bunch of fun to be had there.
It’s kind of a different way to work, which can just lead to more ideas and approaches. Once you close the patch, obviously you loose the loop. But as long as you are working live, you can just record your patch and work from there.
I would almost call it subtractive sampling because you could capture some loops with the delay synced module, but then apply envelopes to the volume on a mixer (instead of triggering a sample). Personally, I think these kinds of workarounds can be productive because my mind gets into a problem solving mode. With that mixer with the mutes and the master clocks with time divisions at hand, you could probably get interesting results by subtractively introducing sections of a sample.
To put it another way, there is an sense in which this is an approach to sampling: