fl.cumsum~

I know a few other people have requested a cumulative sum object, (it might have been @swp1g17). Just putting this here so that its recorded. I did try to do something today where I needed it and struggled to reason around it easily with what objects are there.

Don’t know if you ever found a way to do this, but I’ve ended up using fl.biquad~ (somewhat cryptically) for this and frame-wise deltas:


----------begin_max5_patcher----------
547.3ocyVFsaaBCEF9Z3ovxWmhrAaBouJUSSDhSlqB1Lvzkoplm8YeLnltXk
wJr1IRHxmbfi+7O+GyywQ3s5ShNL5dzCnnnmiihfPt.QCiiv0kmpNV1Aogqz
00BkAux+eFwICDemb+9wfxcPH81GuKmNFT0WKUGEF31PeMnt2LFkLDsozT8M
o5vWaEUF+jKkUjPVgn4oteRYvYRBA8E2k7Rbr6zpYxPUecWecHJHKCEzh0.E
94OedTTK55JOHthBZB5hOAngyCRSZPZn2fF9FuXjkvsPQHvnTGNCWj+9X9Yi
veEX76hTk3G148Uft+XhQaS7bHFW+WnX2hwbOUDtiQdwGOhakeuub2YDwdPQ
2QQjP3xVHIMidgMiR4e77pUUhPJJayxnnbvBlkANP5+J9tg4LMAkkfXIHdHy
IqXYTRluQIMGDx+q7lr7kQIYfFRWClxOCqYq3fryHZOaMlCGgvktLJp+A2hO
Om4XmHWOHj6anNQLxRRKM88hKjG9nT86udCTKW72tFzo6aqFuUixF50xsSzY
jpRiTqtLIhOofqyStRjoTo72jjtcmnEVBmWoymRossjr58LgbyTpDcAVNca8
+Gqj6cflOSSQ3baMGR3HyCR1TJ85qVN81hxllmDscCYCEw1D3QMLwJVACkJ+
PvihaEOIGymCQJasVVi0u12BSL7ob+Kgfq0VDU8xgGOs3YKIzfQUZ2WrozSB
zGJ9k3eASf50.A
-----------end_max5_patcher-----------
1 Like

This is interesting. I don’t understand the maths but it works!

The fl.biquad~ difference eq
y[n] = b[0]x[n] + b[1]x[n-1] + b[2]x[n-2] - a[0]y[n-1] - a[1]y[n-2]

and cumsum
y[n] = x[n] + y[n-1]

=> a[0] = -1, b[0] = 1

and diff
y[n] = x[n] - x[n-1]

=> b[0]=1, b[1]=-1

1 Like

That makes sense!

@o.green you are a true genius, this is exactly what I am looking for.

Probably I should add something specific here. What are people using this for BTW?

Right now I want to create a flexible synth workflow that can render offline so I can use the buffer-based flucoma tools for analysis. The core to this is to be able to create a time-varying phasor signal, that’s where I need the cumsum – turns out @o.green 's biquad hack is perfect for this. As a first step I wanted to implement a non-realtime FM synth (for dataset generation), that’s what you see in fm_nrt.maxpat. You’ll need the other patches as abstractions for it to work. What I like about the idea of fl.phasor~ and fl.sinewave~ is that you then can use these for building many other types of synths with time-varying signals as input (frames).
fl.cumsum~.maxpat (2.7 KB)
fl.phasor~.maxpat (4.6 KB)
fl.sinewave~.maxpat (3.6 KB)
fm_nrt.maxpat (16.1 KB)

Thanks - this has given me a couple of ideas - one for a simpler object that does sums (do we want any other options - like products as well?) and another about custom filters that can be written as expressions (that is probably a bit of a longer/future job, but I’d hope I might be to use the expression stuff to support that.

I’m going to a add PRs for these on GitHub to remind me. I recently made it much easier to set up new objects so expanding the set should be much easier now.

1 Like

I think it would be great to have some kind of a general “lambda” interface, so you can do anything from “x0 + x1” to “x0 * (2 ^ 1/x1)” or whatever you need. Then you only need to implement one object that can cover all cases. But I guess that can be tricky to implement, so I guess a cumsum~ is a good place to start.

Well - filters as expressions could be used for what you want in terms of “lamdas” - whether we think of that as filter or not - that’s captured here:

That one would be a lot more fun to write than the cumulative sum (which is trivial to do), but it’s unclear to me how much work it would be…

On the product question I suppose the question is whether we want fl.cumsum~ only or fl.cumsum~ and fl.cumproduct~ or we make something more like std::accumulate that could do either (or have a limited binary operation to accumulate) - std::accumulate - cppreference.com

Speculatively, something that allows you to do higher order functions from functional programming could solve all these problems in an elegant-ish way.

fl.map~ already exists and kind of does the same thing but just purely for scaling, and in many cases fl.expr~ gives you what you need for anything where its not just about scaling. I think something like fl.reduce~ could be cool, and you get two variables in the box to parse and work with. a bit like js but it’s not particularly idiomatic to Max in that sense. You also often need the index with a reduction to do anything like a cumulative sum. Tricky problem I suppose if the idea is to make something more generic than fl.cumsum~

These likely won’t be rolled into one object. As @o.green has demonstrated - you can do this with a biquad (so by that measure the object isn’t needed at all) but the point is for things to be easy to access, so cumulative sums (or accumulation) to me is one concept and a lambda/reduce/generic filter/whatever clever thing is a second idea so that you don’t have to roll your own accumulator if you are not in super geek mode, but then there’s something where you can if you wish to…

That’s my current thinking anyway. Thoughts?

1 Like

That all makes sense to me :slight_smile:

That sounds great! Personally I am totally okay with just having the fl.cumsum~ as an abastraction from the biquad. If there was only the “roll-your-own” generic object and I needed cumsum often I’d likely make an fl.cumsum~ abstraction anyway as a shortcut.