dynamic GUI, load abstraction dynamically
Hi,
I'm running into two issues I can't seem to solve:
-
Is there a way to dynamically load and clear abstractions?
Let’s say I have multiple synthesizer engines with different GOP settings and sliders.
I’d like to switch between them by always loading just one engine at a time and replacing the GOP of the previous engine. -
I’d like to create a virtual display/dynamic GUI. I know that I can’t hide objects in Pure Data, but I could move the GOP to different sections to give the impression of switching display pages.
The problem is that I have 16 tracks, and each track might need 6–8 pages. That’s already over 100 pages — not including the different synthesizer engines with their own settings for each page.
Altogether, that could easily add up to 400+ pages, which is way too much to handle just by shifting the GOP.
I also considered using one abstraction per track. But that would require showing a GOP inside another GOP, which looks like that won`t work either?
Are there any other options I could try?
[vline~] may not start at block boundaries
@jameslo Pretty sure it is documented here...
Messages are received and run out during an audio block?...... but the resulting instructions are not passed to an object until the next boundary?..... at which time they will be scheduled to be acted upon within the next block if the object can do so?.
I admit in advance that I am not certain that is what is being declared below.
"2.5. scheduling
Pd uses 64-bit floating point numbers to represent time, providing sample accuracy and essentially never overflowing. Time appears to the user in milliseconds.
2.5.1. audio and messages
Audio and message processing are interleaved in Pd. Audio processing is scheduled every 64 samples at Pd's sample rate; at 44100 Hz. this gives a period of 1.45 milliseconds. You may turn DSP computation on and off by sending the "pd" object the messages "dsp 1" and "dsp 0."
In the intervals between, delays might time out or external conditions might arise (incoming MIDI, mouse clicks, or whatnot). These may cause a cascade of depth-first message passing; each such message cascade is completely run out before the next message or DSP tick is computed. Messages are never passed to objects during a DSP tick; the ticks are atomic and parameter changes sent to different objects in any given message cascade take effect simultaneously.
In the middle of a message cascade you may schedule another one at a delay of zero. This delayed cascade happens after the present cascade has finished, but at the same logical time".
http://puredata.info/docs/manuals/pd/x2.htm
And I also wonder whether we are actually able to graph the result properly.... maybe [print~] is the only way as it gets the data from the next block, whereas [tabread] gives data from the last block?
David.
CPU load vs system load
WRT real-time audio, the most important performance factor is: will the next hardware buffer's worth of audio be ready on time?
If we assume a 512 sample hardware buffer and a 48 kHz sample rate, then each hardware buffer takes 10.6666667 ms.
If the audio calculations finish in 1 ms, that's roughly 10% of the available time. If they finish in 5 ms, that's 50%.
RT audio calculations tend to happen in bursts. IIUC (I could be wrong) system CPU monitors are looking for sustained CPU activity, which does not characterize RT audio. So the system monitor might tell you that the system isn't very busy, but the DSP thread might actually be stressed.
For instance, I just ran a bunch of DSP in SuperCollider and it reported about 38% CPU use, but the system task monitor reported 4%. (But htop showed one CPU core with high activity, and the rest mostly idle... so a single CPU usage number that aggregates all the CPU cores can also under-report.)
I think I remember reading here that Pd does its audio calculations outside of the audio driver's callback, and uses the callback only to copy data, meaning that audio subsystems like JACK in Linux might significantly underreport CPU usage. So the whole thing is a bit of a tricky question. I don't know how Purr Data is measuring CPU use.
hjh
how would you recreate this mixer channelstrip abstraction?
@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
and dwR
go to a separate [diskwrite~]
abstraction which i use to record audio. the "p" (and p1-p8) defines that any channelstrip that has p
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?
trying to set PageUp/PageDown to get to the top and the bottom of the canvas - need it in abstraction instead of mainview due to display space considerations
ok, found that
0 = GOP OFF + hide names OFF
1 = GOP ON + hide names OFF
2 = GOP ON + hide names ON
i tried to find a way to output the canvas GOP settings to PD console via print but couldn't figure it out. is there no documentation about dynamic GOP changing within PD documentation?
Copy larger array (1mb) to smaller array (64kb) with visual definable startpoint?
Hi, here's what i'm working with: I've got sixteen 64kb arrays functioning as loopers.
Now, recording to them is sometimes quite challenging, if there's a quick sound, I might "blink and miss it", and then have to ask for that sound to be played again, hoping I'll be quick enough to catch it (I basically use a metronome to record, i.e. when I click on "X" (tgl) - recording starts, and then when I click on "X" (tgl), if i'm lucky, the waveform I'm seeing in the array stays.
Now, fixing that would be pretty cool (I can provide a screenshot at the bottom of this post and am open to any suggestions) but I'm now looking at this idea of "record a large amount of audio, and set a copypoint and copy a 64kb chunk from the copypoint (startpoint, really) onwards to a 64kb array.
So, how would one go about doing that? I'm currently using this to copy between the sixteen loopers. So I click on one looper number, and then click on another looper number, and a copy from A to B is made:
that's pretty great and useful!
but now i'm looking to finally have this "long array", with maybe a slider underneath it to define what the startpoint of the copy is, and only copy the next 64kb chunks after the startpoint.
so is it [array sum (startpoint) (specific length, i.e. 64kb) (arrayname)]
that i would then be using, with a slider defining the startpoint, and a hard [64000(
to get "from there"?
so here's the [metro 2000]
I use to sample - what I'd prefer to do is record one full 64kb chunk and then if the chunk is visible already, and I press [tgl]
- the recording stops there. instead, the visible chunk might get overwritten, if i'm unlucky enough:
should i be using some sort of method of splitting the [tgl]
into a [start(
and a [stop(
? i'm not 100% sure. or could i somehow time the 64kb sampling so that if i press stop, and the tabwrite~ gets to the end of the array, it stops when i untick the [tgl]
?
Question about [tabread4~]
@ddw_music said:
@dfkettle said:
Edit: My audio interface is running at 44,100 (a Steinberg UR22), and so are Audacity and Pure Data.
@ddw_music I ran your test patch and it seems that 'phasor~' runs a tiny bit slow on my machine
Nope.
Pd's control block resolution is 64 samples. [timer] can report only on 64 sample boundaries.
Now... what is 44100 / 64? ... It's 689.0625.
This is not an integer.
Therefore there is no way, at 44.1 kHz, that a number of control blocks can add up to exactly one second.
When I did it in the morning, my internal soundcard supports only 48 kHz... which is a multiple of 64.
Gotcha. I changed the SR to 48000 and now the test shows exactly 1000 ms.
There will be no deviation in pitch based on the divisibility of the sample rate. That isn't how soundcards work.
even though the CPU usage is only fluctuating between 5 and 15%.
That isn't how soundcards work either.
I know that, but I thought maybe the CPU might be too busy and the data wasn't being sent to the audio interface fast enough. So I checked the CPU usage in the Windows system monitor.
Using Pi GPIO pins with pd
Hi, have you already seen this thread:
https://forum.pdpatchrepo.info/topic/12112/raspberry-pi-gpio-and-puredata-does-it-work ?
Taking the last post by @alexandros into account, I searched a little on GitHub and found this:
https://github.com/pd-l2ork/pd/search?q=gpio
I have never used pd-2ork though, but maybe the disis-gpio object from there could be compiled..?
Let me know if you have any success or more questions. Good luck!
Collection of Pd internal messages, dynamic patching
An explanation of [donecanvasdialog( for canvas properties, including and most important graph-on-parent:
@Maelstorm wrote:
You can use [donecanvasdialog( to change the gop properties. When you right-click on a patch and choose Properties, all of that stuff is contained in the [donecanvasdialog( message. The format is this:
[donecanvasdialog <x-units> <y-units> <gop> <x-from> <y-from> <x-to> <y-to> <x-size> <y-size> <x-margin> <y-margin>(
The gop argument is 0 = gop off; 1 = gop on, show arguments; and 2 = gop on, hide arguments.
And there is a phenomenal patch-demo reposted by @whale-av
https://forum.pdpatchrepo.info/topic/5746/change-graph-on-parent-dimentions-from-inside/2
thx
Copying data from one buffer array to another buffer array
@emviveros said:
Seems like maxlib/arraycopy have a special implementation for copy entire arrays.
I think it depends on the number of elements being copied.
maxlib/arraycopy accepts start/size parameters with every copy request -- so it has to validate all the parameters for every request (https://github.com/electrickery/pd-maxlib/blob/master/src/arraycopy.c#L81-L166). This is overhead. The copying itself is just a simple for loop, nothing to see here.
[array get] / [array set], AFAICS, copy twice: get copies into a list, and set copies the list into the target.
So we could estimate the cost of arraycopy as: let t1 = time required to validate the request, and t2 = time required to copy one item, then t = num_trials * (t1 + (num_items * t2)) -- from this, we would expect that performance would degrade for large num_trials and small num_items, and improve the other way around.
And we could estimate the get/set cost as num_trials * 2 * t2 * num_items. Because both approaches use a simple for loop to copy the data, we can assume t2 is roughly the same in both cases. (Although... the Pd source de-allocates the list pointer after sending it out the [array get] outlet so I wonder if the outlet itself does another copy! No time to look for that right now.)
If you have a smaller number of trials but a much larger data set, then the for
loop cost is large. Get/set incurs the for
cost twice, while arraycopy does it once = arraycopy is better.
In the tests with 100000 trials but copying 5 or 10 items, the for
cost is negligible but it seems that arraycopy's validation code ends up costing more.
hjh