so i've been fooling around with this mixer channelstrip (kinda) for quite some time. it has global volume and channel volume, and sends to other channelstrips (effects). but since i have 26 of those (and they all have color slider control) - i'm wondering, are there better solutions than having 26 channelstrips with 14 sliders with color schemes each?
-
how would you recreate this mixer channelstrip abstraction?
-
@esaruoho If you are trying to save CPU than I would just separate UI and DSP, run the UI in its own instance of PD and DSP in another, communicate between them with [netsed]/[netreceive], there comes a time in PD when you just have to either separate UI and DSP or sacrifice. Beyond that it is difficult to say, I do not know what your needs are and what sacrifices are acceptable. What are your requirements? I can optimize these patches in a dozen different ways but I have no idea if any of them will meet your needs since I do not know what your needs are or even why you are trying to change things beyond a vague notion of there possibly being something better.
-
@oid said:
@esaruoho If you are trying to save CPU than I would just separate UI and DSP, run the UI in its own instance of PD and DSP in another, communicate between them with [netsed]/[netreceive], there comes a time in PD when you just have to either separate UI and DSP or sacrifice. Beyond that it is difficult to say, I do not know what your needs are and what sacrifices are acceptable. What are your requirements? I can optimize these patches in a dozen different ways but I have no idea if any of them will meet your needs since I do not know what your needs are or even why you are trying to change things beyond a vague notion of there possibly being something better.
ok. i have heard about this UI DSP separation. so.. is it a case of every single slider for instance needs to do a
[netsend]
to some other abstraction that only does DSP? or have two separate patches altogether, one for UI and one for DSP? sorry, i'm really vague on this.So, my main painpoints with the current channelstrip is that when I set up 16 "LFOs" to "breathe" up and down the volume slider (which also has slider-color-changing while it is moved from 0 to 1) - when i have more than 4 of these LFO counters cycling from 0...1 on the channelstrips, all sliders stop updating. it might be 4, 8 or 12, but by the time i try to get all 16 of the looper volumes to cycle from 0...1 (my "breather" has a setup of cycling from "min-max every 2 seconds" to "min-max every 60 seconds") -- and that to me makes me think that the UI is not as optimized as possible.
i keep hearing that ELSE library supposedly has some larger crossmatrix/channelstrip that i could use, but i have not looked at it.
so ideally i'd prefer to take the channelstrip even further, i.e. have all effect sends be modulatable (well, that word where the effects have LFO modulation) so i could have even larger more complex things going on where the channelstrips that receive audio from loopers, are sent to specific sends like reverbs, delays and so on. this kind of larger modulation on all parameters would be really useful.
the way the channelstrip is built is that the
dwL
anddwR
go to a separate[diskwrite~]
abstraction which i use to record audio. the "p" (and p1-p8) defines that any channelstrip that hasp
enabled, is sending to all the other loopers - so in that case, any audio that goes to a channelstrip, can be sampled into the 64kb loopers (16 of them).also i have thechannelstrip labels (i.e. volume slider name) dynamically written to, so i can always have them easily understandable / informative.
here's the "init state". i use bunches and bunches of loadbang -> message -> senders to get them to a specific state. .one thing i've been toying around as an idea is to incorporate highpass and lowpass filters to the channelstrips, and EQ. but i haven't figured out how to solve the EQ issue so that the single band peak EQ could be incorporated into such a small formfactor ( the width is only 38 and height is 189 so it's hard to conceive how an EQ could be usable there).
i also have for the 16 channelstrip looper instances, BCR2000 + BCF2000 volume slider control and so on. but i'm willing to take the whole setup "to the dock" and rewrite it, if i could be sure that it will be lighter on the cpu..
so yeah, i do only have a vague notion of "maybe it could be better, i'm not sure?".. but i've not yet seen much netsend + netreceive stuff so i'm not entirely familiar how it could be done and how much i need to rewrite (i.e. does everything need to be netsend+netreceived with a complete split of DSP and UI, to reap the benefits, or can i just try it with the 16 loopers and see what happens?
-
@esaruoho Generally I attach a symbol to the UI element's name and then run them to a [send] which sends to a single [netsend] but that is mostly because the [send] tends to be useful elsewhere in the UI, it could be replaced with the [netsend] itself. All of your label updates and the like can be handled through this.
The else channelstrip and other such externals will probably not help much here since your issue is that you are running out of time between blocks and they will only help during the DSP block, you still have all those UI updates to do which are where you are running into problems. It is a lot of work to separate the UI and the DSP on a large project and it sucks to do but sometimes it needs to be done but maybe someone else will have a simpler solution for you. There could be other/better ways to improve things, hard to say without seeing your entire patch but I assume your channel strip is an abstraction so it would be much work to test it on just that one abstraction to see what happens.
-
@esaruoho wrote:
16 "LFOs" to "breathe" up and down the volume slider
How does your modulation LFO look like?
Is the modulator a signal or control-object?
Does it offset or master the fader ?Did you try what I mentioned in your other thread?
https://forum.pdpatchrepo.info/topic/14291/need-a-simpler-way-to-change-slider-background-color-when-on-and-off/6If you update the GUI on each block
= SR/64 = 44100 /64=689 times per second,
this is overkill and is going to drag down performance, even if the two parts run asynchronously.
<25 frames per second should be enough for the GUI.Setting many faders and their colour once in a while should not cause any trouble. Limiting the update rate might be enough to run stable. (see the patch below)
Benefit from separating GUI- and audio-parts across two PD-instances would be, if the GUI is lagging, audio still runs without drop-outs as PD-instances run asynchronous.
Ideally run the PD-instances on different CPU-cores (and audio in higher priority) by setting this in the operating system.
(btw offtopic, to complicate things even further: in case you are not aware of it:
there is also the [pd~] object, which does simple multithreading, splitting patches across the CPU-cores. But the parts are running synchronous.
Running one instance of Pure Data only, without [pd~], everything runs on one core only.)For real-time audio a synchronous chain between input and output is important.
So no, unless you know what you are doing, don't split audio into several PD-instances.
(but yes, on different cores with [pd~], in case the audio-part runs out of CPU-time and you don't want to increase latency).
Sth like this is what I thought about in the other thread, slowing down GUI-update-rate with [metro] and [snapshot~]
and detaching it from the deterministic chain with [pipe],
while maintaining signal-rate amplitude modulation:
fader-abstraction.pd
slider-guts.pd(I don't have Vanilla here right now, and doesn't work on web-PurrData,. But should work on Vanilla, if there is no bug!?)
EDIT: changed [pipe 5] and added [change] and set fader properties to "jump on click" -
( the width is only 38 and height is 189 so it's hard to conceive how an EQ could be usable there).
number boxes?
popup window?
incorporating tabs into the bpatcher?
alt-dragging a sllider for more resolution than pixels?
-
@lacuna said:
@esaruoho wrote:
16 "LFOs" to "breathe" up and down the volume slider
How does your modulation LFO look like?
Is the modulator a signal or control-object?
Does it offset or master the fader ?so this is how it works. when i move the amplitude slider, the toggle toggles on, and the process starts.
and here's what receives it (the plom1s, plom1a and plom1m)
i'm fairly sure this could be done in a better way.
and nope, it doesn't take into consideration "what's always there", that's what the channelstrip global volume is for, i.e. this modifies the "track volume" if you will.
and one slider changes the speed of the counter, and one slider changes the amplitude of the results, i.e. if i put it to max, it'll be 0...1 otherwise it'll be something else.
i hope this sheds some light to this. i'm fairly sure this could be done better and easier.
-
@lacuna said:
Did you try what I mentioned in your other thread?
https://forum.pdpatchrepo.info/topic/14291/need-a-simpler-way-to-change-slider-background-color-when-on-and-off/6hi, i tried all two or three different methods i was given for changing slider background colour, but unfortunately every single one ground the UI to a halt, even made it just so sluggish that macOS decided PD had become unresponsive/crashed. so i had to basically load the abstractions and remove the changes.
but, since you sent a different method, i'll try that next!
Benefit from separating GUI- and audio-parts across two PD-instances would be, if the GUI is lagging, audio still runs without drop-outs as PD-instances run asynchronous.
actually, even though GUI is lagging, in my case, the audio is still playing without any issues. I'd have started panicking last year and started reducing "all kinds of stuff" if the GUI-sluggishness affected live audio during a liveperformance.
(btw offtopic, to complicate things even further: in case you are not aware of it:
there is also the [pd~] object, which does simple multithreading, splitting patches across the CPU-cores. But the parts are running synchronous.
Running one instance of Pure Data only, without [pd~], everything runs on one core only.)if i understand correctly, it might be that an Apple Silicon M1 would be good with multithreaded cores. i'll have to see what
[pd~]
really does, i.e. can i put content into it and how. this is a lot of new stuff!Sth like this is what I thought about in the other thread, slowing down GUI-update-rate with [metro] and [snapshot~]
and detaching it from the deterministic chain with [pipe],
while maintaining signal-rate amplitude modulation:what's so weird is that all these "step with a timer, instead of 100% realtime" solutions, so far, have ground UI/PD to a halt. i don't know what to think! i mean, is it just that there's so many different metronomes for this (like 200+) that it just is too much at one go..
the only thing i can think of is creating a patching logic where if i activate the breather, the colour-changing is halted. maybe that's the solution that would be less flashy GUI-wise, but would keep the app running.
You gave a lot, and I appreciate it, I'll try and have a look as to how I could incorporate them. thanks loads!
-
@Obineg said:
( the width is only 38 and height is 189 so it's hard to conceive how an EQ could be usable there).
number boxes?
popup window?
incorporating tabs into the bpatcher?
alt-dragging a sllider for more resolution than pixels?i'm using very visual EQs which just let me draw a peak EQ for each of the loopers, and for my purposes they need to be available, instead of opened and closed with clicks (popup windows). also hiding inside tabs would be problematic.
granted, if i was using numberboxes and sliders instead of this visual peak EQ ([else/bicoeff]
), they could be incorporated easily into the my 16 looper abstractions.
maybe the solution is to have an[else/circle]
and have it be tiny and talk to the bicoeff.. -
@esaruoho This could help, I reduced the color resolution so we only have 9 shades of grey and far fewer updates and I also stuck the slider and the color logic in a single abstraction to make things neater. Just run the abstraction with arguments for name and unique ID ([sloid plom1 $0] etc) . Went lazy on label color and just gave it two colors but simple enough to change if desired.
sloid.pd
-
@esaruoho We could also take this in a more functional way and use a single bit of logic to calculate the colors for all of the sliders;
This may be a considerable improvement depending on how exactly pd handles abstractions. From what I can tell* lesser used bits of a patch slowly get buried in the stack or what ever data structure pd keeps your patch in so a slider you just used will be right at the tips of pd's fingers while one that has not been used in an hour it will have to dig out which takes time. Having all of the abstractions use the same piece of code for the coloring will mean the coloring code will always stay near the top of the stack or what ever data structure pd uses here. But pd may use abstractions like functions (I suspect not) and using any instance of an abstraction may keep the abstraction code close by for other instances. This also reduces how much code pd has to pay attention too, cuts ~3000 objects and their wires from the data path which I suspect will help some.*I don't actually know how this works, this is just reasoned out through experimentation and playing with the various means pd gives us to time how long a bit of a patch takes to execute, I could be way off. Either way getting your colors from a lookup table like I did will be a decent improvement on speed, saves some math and converting to the numbers to hex.
Edit: think I fixed all the mistakes in the example now...
-
@oid said:
From what I can tell* lesser used bits of a patch slowly get buried in the stack or what ever data structure pd keeps your patch in so a slider you just used will be right at the tips of pd's fingers while one that has not been used in an hour it will have to dig out which takes time.
That sounds odd to me. An outlet is a pointer of a linked list of pointers to inlets (m_obj.c, line 308 ff.). It would be weird if it's altering the storage structure based on frequency of usage.
You might be seeing some effect from RAM caching on the CPU...?
hjh
-
@ddw_music Like I said, I don't actually know how this works All I know is that according to the various timer objects more frequently run code executes faster. I suppose that means this effect is architecture and system dependent but likely present on all modernish systems to some degree? My conjecture was partially included to illicit responses from more knowledgeable people.
I am not good enough with pointers yet to make much sense of the pd source, working on it and Miller's videos explaining the innards of pd are a great help but I still get overwhelmed by all those asterisks and figuring out what they all point at.
-
@oid FWIW I tested the performance of banging one instance of a clone vs banging (randomly) all of them. Results were inconsistent (within margin of error).
hjh
-
@ddw_music I think the effect I am seeing is maybe caused by simple scheduling on the CPU combined with my test method, my clicking the bang repeatedly kept the scheduler paying attention and then when I left it alone for a bit it was not getting on the CPU as quickly or something like that, putting the CPU governor to performance decreased the effect noticeably. I would have had a picture but I banged an until with nothing to stop it, oh well. So I guess that last idea of mine will only improve things if cutting the object count by ~3000 actually helps and with that I am assuming the loadbang stuff is out of the picture after object creation since with the loadbang logic object count does not drop much.
-
@oid Hard to say... I don't know the internals either.
It's an educated guess, but I look at it in terms of, how are objects reachable? The target of a connection is reachable from the upstream object's outlet's list of targets. A [receive] is reachable from the list of objects associated with the symbol.
The suggestion is that some of these targets may be, somehow, made harder to access and others made easier. That seems really complex (i.e. breakable) and likely to cause more problems than it solves. I'm guessing that there's no "reachability" path in pd that depends on the object's frequency of access.
I haven't looked deep at the code, but it looks to me like outlets and "bindlists" ([send] / [receive]) both use linked lists, which are O(n) for traversal, insertion and deletion.
For the main question in the thread, I think the most important things will be: 1/ don't push updates through unless the display is really changing (i.e. use [change]); 2/ control the rate of updates ([cyclone/speedlim]); and 3/ if necessary, split the GUI to a separate process.
hjh
-
@oid said:
@esaruoho This could help, I reduced the color resolution so we only have 9 shades of grey and far fewer updates and I also stuck the slider and the color logic in a single abstraction to make things neater. Just run the abstraction with arguments for name and unique ID ([sloid plom1 $0] etc) . Went lazy on label color and just gave it two colors but simple enough to change if desired.
sloid.pd
hi! i kinda panicked with the complexity of this, but then realized i could just take the colouring logic and replace one
[sliderc]
with[sliderc2]
with only the colouring logic (admittedly, it's not looking as awesome, but it works (i might eventually need to change it to maybe 18 colors instead of 9 colors). and now i can have 16 breathers without the UI grinding to a halt. do you think 18 shades of grey will still work or will that be too much?thank you very much! i didn't change all sliderc's to this, since the volume ones for the 16 loopers were the ones that were causing the issues, so if i come across more problematic sliders, i'll replace them one by one.
-
@esaruoho 18 will probably be fine and you can probably even go higher without issue, the main things which makes this more efficient is the lookup table built around the [list store] saving you the math and conversion to hex and the [change] filtering out the duplicate output, The only reason I picked 9 colors was it kept me from having to think much, the 9 shades of gray and the old coloring number system was a zero thought required solution on my part.