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