PD-2-ThoughtMap (a patch and its children as a plantuml-usecase) (Linux Shell Script/Package) (v0.1.1 update below)
Background:
The project I have been working on, for over a year now, began to be more complex than I was able to visualize.
As such, I was required to build something which would allow me to "see" it in its entirety.
NOT the audio stream, passing from one object to another, nor the variables, nor sends.
But rather, I needed to see my objects, i.e. subpatches and abstractions themselves. And how they were embedded within one another. I needed to see the "programmatic-flow" from one sub-object to the next.
Which is how this came about. Examples:
simple example
1.poly.synth
Preface:
Miller's bi-recursive/toroidal loop function, i.e. going "../" up and/or going down "/x/y/z.pd" the embedded object-tree has (thus far eluded me. So the patch for now only recurses down the tree.
Purpose:
By setting up a "Send-To" link to ".pd" filetypes (within Linux), one is able to right-click and send any ".pd" file to the pd2thoughtmap shell script and after a brief time (depending on the complexity of the patch). the "defaultbrowser" will open with a plantuml (http:///www.plantuml.com) usecase diagram showing the "object-flow" from one nested object to the next (clipping branches which have no embedded abstractions).
My hope has been the benefit I have/can gain from this tool, will also benefit the pd community and folks in being able to better "see" what they have done. And how to better organize their patches to suit their vision, the need of the project, or just plain Efficiency.
Instructions:
1-Download the pd2thoughtmap.zip file: pd2thoughtmapv0.1.zip
2-Unzip the file into the /root/pd-externals directory;
3-Right-click on a ".pd" file and go to ~"Configure Send-To" or the equivalent for your linux system;
4-Symlink from the /root/pd-externals/pd2thoughtmap/pd2thoughtmap shell script to the Send-To folder for ".pd" files
5-Right-click on a .pd file and "Send-To pd2thoughtmap";
6-After a pause, your default browser will open with the thoughtmap in a tab. (If your browser is already open it will just open another tab).
note: file processing is managed in the /tmp/pd2thoughtmap folder so unloaded at shutdown.
May this tool expedite your auditory "vision" and make it easier for you to comprehend.
Peace, Love, and Music through us all,
Scott
Footnotes:
It recurses down (the directory-tree finding descendants) just fine but will not go up (find predecessors/ancestors).
It will not recurse abstractions if the filenames have more than one period (i.e. the one in the ".pd" suffix).
It Excludes native pd abstractions/classes, ex. [adc~], etc., if they are 1) on the res/objectlist.txt, 2) a ".pd_linux" file in the pure data paths, i.e. "/root/pd-externals/", "/usr/lib/pd/extra/", or "/usr/lib/puredata/". or 3) manually entered into the "res/exclude.txt" file (in the case where one abstraction is repeated many times and you want to ignore it).
If using the command line, there are four total parameters available (to be used all together): $1=the absolute path to the file, $2={0|1|2,3} to indicate if you want "abs and subpatches", "abs only", "subpatches only", or all pd object types, ex. messages, floatatoms, etc; and $3=the height of the image in pixels, and $4=the width of the image in pixels.
If you want me to debug something, please, attach the outputted .png and the /tmp/pd2plantuml/log.txt to your post.
If you find it outputting things that should have been excluded, you can try to eliminate them by adding the object name to the exclude.txt file. This inconsistency is derived from my complete knowledge of the pd file structure. Perhaps I will address it in the future.
I need to work on the original patch for a while, so will update this patch over time and get back with you when I can.
Tally-Ho! And Joy!
-S
Is there a function that works like a table but with only one value?
in short: it's 1 float stored in 1 object of a separate data structure referenced by a pointer in each value object
in longer: when you create a value object with a given name. it checks to see whether a second class called vcommon has any objects that share the same name as the new value object. If not, it creates a vcommon object with that name and stores the float value inside. Then the value stores the pointer to this float and looks up that float using a pointer whenever it needs to modify or get the value (as do all of the other value objects that share the same name). The vcommon object knows how many value objects share it's name (a "reference count") and when the last value object with the same name is deleted, so is the vcommon object
How to create multiple objects at once? Many objects with increasing arguments?
@lacuna I am about to be away without internet for 3 days...... so...... I will describe how it works and post another example....
Each object that you create in the subpatch has a reference within Pd...... a number... which depends on the order in which they are created..... so.....
Your 123 objects will have numbers 1-123..........
But you want to add some other objects. If you add an [outlet~] or [*~ 0.3] before you add your abstractions then that will be object 1 and your abstractions will be objects 2-124. You must be rigorous about the order in which you place the objects.
In this example......... example.pd There are already 3 objects placed in the sub-patch...... open [pd mixer_final] to have a look.
The patch then builds the objects and connects them.....
There is a [loadbang] to say how many of each object should be created, and that creates a [matrix~] with the correct number of inputs and outputs.
Lots of error messages appear in the terminal because the rest of the patches are missing... it does not matter for this example.
The [connect( messages are formatted like this..... [connect "object number" "outlet number" "object number" "inlet number"( and the inlet and outlet numbers are counted from 0-n...... first one "0"......
I do hope that is all makes sense!
Hit the bang at the top of the patch to see everything created in the sub-patch......
David.
Loading a folder of audio files
@RonHerrema Hello again Ron......
Are you planning to have a main folder, with sub-folders all containing tracks, or are you expecting to just pick folders at random from anywhere on your computer.
If you want to pick from absolutely anywhere then you have three problems....
Most folders will have no wav files.........
Some folders will have wav files at the wrong sample rate....
Most folders containing wav files will contain other files as well... album art, etc.
Anyway..... in "cart" the playlist window is cleared and re-populated as each folder is opened.
If you want to bang a message box you need to give each one a [receive] object and then build a patch to send bangs to those objects. That patch is easy using [random]. The track name will always display in "cart" already. The number of tracks can be known (already the tracklist populator stops when it has created the messages in tracklist).
So you need to add (using the populator) a receive object for each message, place it into "tracklist" and attach (connect) each one to its message.
Either you should do this.........
The populator creates the message, connects it to the [s trackplay] object, creates the [receive 1] object and connects it to the message........ and moves on.
Or this....... the populator runs as in cart, but you add a counter, and when it has finished (how do you know, do you just put a delay and hope) it builds the [receive objects and connects them.
I reckon the first is easier. [s trackplay is object 0 on the page and each message is 1-n for the connect message. You need to change the numbers for the connect messages.......
the populator will build..
[s trackplay] (this is object 0)
[message 1] (this is object 1)
connect object 1 to object 0
[receive 1] (this is object 2)
connect object 2 to object 1
[message 2] (this is object 3....... in "cart" it was object 2 but [receive 1 has been created first)
connect object 3 to object 0
[receive 2] (this is object 4)
connect object 4 to object 3
etc. and it will stop when no more names arrive.
You will need a counter though (don't forget to reset it when the next folder is loaded) so that random can have the right argument. [random x].
You can use the right outlet of [readsf~] to bang out the next number from [random] and start the next track..............another counter and a calculation (when tracks played == track count +1) load the next folder.......... etc.......
Have Fun!
David.
use of threads for i²c I/O external : looking for a good strategy
@nau Hi, same boat (I don't know much about Pd internal functions & pthread), but maybe you can try to see if this external (really similar to my template, but this time to fetch real data for my HiCu project).
Look for m_clock / m_interval and clock_delay.
// ==============================================================================
// gac.c
//
// pd-Interface to [ 11h11 | gac ]
// Adapted by: Patrick Sebastien Coulombe
// Website: http://www.workinprogress.ca/guitare-a-crayon
//
// Original Author: Michael Egger
// Copyright: 2007 [ a n y m a ]
// Website: http://gnusb.sourceforge.net/
//
// License: GNU GPL 2.0 www.gnu.org
// Version: 2009-04-11
// ==============================================================================
// ==============================================================================
#include "m_pd.h"
#include <usb.h> //http://libusb-win32.sourceforge.net
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pthread.h"
#include "../common/gac_cmds.h"
// ==============================================================================
// Constants
// ------------------------------------------------------------------------------
#define USBDEV_SHARED_VENDOR 0x16c0 /* VOTI */
#define USBDEV_SHARED_PRODUCT 0x05dc /* Obdev's free shared PID */
#define DEFAULT_CLOCK_INTERVAL 34 /* ms */
#define OUTLETS 11
#define USBREPLYBUFFER 14
unsigned char buffer[USBREPLYBUFFER]; //accessible everywhere
// ==============================================================================
// Our External's Memory structure
// ------------------------------------------------------------------------------
typedef struct _gac // defines our object's internal variables for each instance in a patch
{
t_object p_ob; // object header - ALL pd external MUST begin with this...
usb_dev_handle *dev_handle; // handle to the gac usb device
void *m_clock; // handle to our clock
double m_interval; // clock interval for polling edubeat
double m_interval_bak; // backup clock interval for polling edubeat
int is_running; // is our clock ticking?
void *outlets[OUTLETS]; // handle to the objects outlets
int x_verbose;
pthread_attr_t gac_thread_attr;
pthread_t x_threadid;
} t_gac;
void *gac_class; // global pointer to the object class - so pd can reference the object
// ==============================================================================
// Function Prototypes
// ------------------------------------------------------------------------------
void *gac_new(t_symbol *s);
void gac_assist(t_gac *x, void *b, long m, long a, char *s);
void gac_bang(t_gac *x);
void gac_bootloader(t_gac *x);
static int usbGetStringAscii(usb_dev_handle *dev, int ndex, int langid, char *buf, int buflen);
void find_device(t_gac *x);
// =============================================================================
// Threading
// ------------------------------------------------------------------------------
static void *usb_thread_read(void *w)
{
t_gac *x = (t_gac*) w;
int nBytes;
while(1) {
pthread_testcancel();
if (!(x->dev_handle)) find_device(x);
else {
nBytes = usb_control_msg(x->dev_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
EDUBEAT_CMD_POLL, 0, 0, (char *)buffer, sizeof(buffer), DEFAULT_CLOCK_INTERVAL);
if(x->x_verbose)post("thread read %i bytes", nBytes);
//post("%i b", nBytes);
}
}
return 0;
}
static void usb_thread_start(t_gac *x) {
// create the worker thread
if(pthread_attr_init(&x->gac_thread_attr) < 0)
{
error("gac: could not launch receive thread");
return;
}
if(pthread_attr_setdetachstate(&x->gac_thread_attr, PTHREAD_CREATE_DETACHED) < 0)
{
error("gac: could not launch receive thread");
return;
}
if(pthread_create(&x->x_threadid, &x->gac_thread_attr, usb_thread_read, x) < 0)
{
error("gac: could not launch receive thread");
return;
}
else
{
if(x->x_verbose)post("gac: thread %d launched", (int)x->x_threadid );
}
}
//--------------------------------------------------------------------------
// - Message: bootloader
//--------------------------------------------------------------------------
void gac_bootloader(t_gac *x)
{
int cmd;
int nBytes;
unsigned char bootloaderbuffer[8];
cmd = 0;
cmd = EDUBEAT_CMD_START_BOOTLOADER;
if (!(x->dev_handle)) find_device(x);
else {
nBytes = usb_control_msg(x->dev_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
cmd, 0, 0, (char *)bootloaderbuffer, sizeof(bootloaderbuffer), DEFAULT_CLOCK_INTERVAL);
}
}
//--------------------------------------------------------------------------
// - Message: bang -> poll gac
//--------------------------------------------------------------------------
void gac_bang(t_gac *x) {
int i,n;
int replymask,replyshift,replybyte;
int temp;
for (i = 0; i < OUTLETS; i++) {
temp = buffer[i];
switch(i) {
case 0:
replybyte = buffer[8];
replyshift = ((0 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 1:
replybyte = buffer[8];
replyshift = ((1 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 2:
replybyte = buffer[8];
replyshift = ((2 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 3:
replybyte = buffer[8];
replyshift = ((3 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 4:
replybyte = buffer[9];
replyshift = ((0 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 5:
replybyte = buffer[9];
replyshift = ((1 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 6:
replybyte = buffer[9];
replyshift = ((2 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 8:
temp = buffer[10];
replybyte = buffer[13];
replyshift = ((0 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 9:
temp = buffer[11];
replybyte = buffer[13];
replyshift = ((1 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
case 10:
temp = buffer[12];
replybyte = buffer[13];
replyshift = ((2 % 4) * 2);
replymask = (3 << replyshift);
temp = temp * 4 + ((replybyte & replymask) >> replyshift);
break;
}
outlet_float(x->outlets[i], temp);
}
}
//--------------------------------------------------------------------------
// - The clock is ticking, tic, tac...
//--------------------------------------------------------------------------
void gac_tick(t_gac *x) {
clock_delay(x->m_clock, x->m_interval); // schedule another tick
gac_bang(x); // poll the edubeat
}
//--------------------------------------------------------------------------
// - Object creation and setup
//--------------------------------------------------------------------------
int gac_setup(void)
{
gac_class = class_new ( gensym("gac"),(t_newmethod)gac_new, 0, sizeof(t_gac), CLASS_DEFAULT,0);
// Add message handlers
class_addbang(gac_class, (t_method)gac_bang);
class_addmethod(gac_class, (t_method)gac_bootloader, gensym("bootloader"), A_DEFSYM,0);
post("bald-approved gac version 0.1",0);
return 1;
}
//--------------------------------------------------------------------------
void *gac_new(t_symbol *s) // s = optional argument typed into object box (A_SYM) -- defaults to 0 if no args are typed
{
t_gac *x; // local variable (pointer to a t_gac data structure)
x = (t_gac *)pd_new(gac_class); // create a new instance of this object
x->m_clock = clock_new(x,(t_method)gac_tick);
x->x_verbose = 0;
x->m_interval = DEFAULT_CLOCK_INTERVAL;
x->m_interval_bak = DEFAULT_CLOCK_INTERVAL;
x->dev_handle = NULL;
int i;
// create outlets and assign it to our outlet variable in the instance's data structure
for (i=0; i < OUTLETS; i++) {
x->outlets[i] = outlet_new(&x->p_ob, &s_float);
}
usb_thread_start(x); //start polling the device
clock_delay(x->m_clock,0.); //start reading the buffer
return x; // return a reference to the object instance
}
//--------------------------------------------------------------------------
// - Object destruction
//--------------------------------------------------------------------------
void gac_free(t_gac *x)
{
if (x->dev_handle) usb_close(x->dev_handle);
freebytes((t_object *)x->m_clock, sizeof(x->m_clock));
while(pthread_cancel(x->x_threadid) < 0)
if(x->x_verbose)post("gac: killing thread\n");
if(x->x_verbose)post("gac: thread canceled\n");
}
//--------------------------------------------------------------------------
// - USB Utility Functions
//--------------------------------------------------------------------------
static int usbGetStringAscii(usb_dev_handle *dev, int ndex, int langid, char *buf, int buflen)
{
char asciibuffer[256];
int rval, i;
if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + ndex, langid, asciibuffer, sizeof(asciibuffer), 1000)) < 0)
return rval;
if(asciibuffer[1] != USB_DT_STRING)
return 0;
if((unsigned char)asciibuffer[0] < rval)
rval = (unsigned char)asciibuffer[0];
rval /= 2;
/* lossy conversion to ISO Latin1 */
for(i=1;i<rval;i++){
if(i > buflen) /* destination buffer overflow */
break;
buf[i-1] = asciibuffer[2 * i];
if(asciibuffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
buf[i-1] = '?';
}
buf[i-1] = 0;
return i-1;
}
//--------------------------------------------------------------------------
void find_device(t_gac *x) {
usb_dev_handle *handle = NULL;
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
for(bus=usb_busses; bus; bus=bus->next){
for(dev=bus->devices; dev; dev=dev->next){
if(dev->descriptor.idVendor == USBDEV_SHARED_VENDOR && dev->descriptor.idProduct == USBDEV_SHARED_PRODUCT){
char string[256];
int len;
handle = usb_open(dev); /* we need to open the device in order to query strings */
if(!handle){
error ("Warning: cannot open USB device: %s", usb_strerror());
continue;
}
/* now find out whether the device actually is gac */
len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string));
if(len < 0){
post("gac: warning: cannot query manufacturer for device: %s", usb_strerror());
goto skipDevice;
}
post("::::::%s", string);
if(strcmp(string, "11h11") != 0)
goto skipDevice;
len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string));
if(len < 0){
post("gac: warning: cannot query product for device: %s", usb_strerror());
goto skipDevice;
}
if(strcmp(string, "Gac") == 0)
break;
skipDevice:
usb_close(handle);
handle = NULL;
}
}
if(handle)
break;
}
if(!handle){
post("Could not find USB device 11h11/gac");
x->dev_handle = NULL;
} else {
x->dev_handle = handle;
post("Found USB device 11h11/gac");
}
}
Cheers
How to install externals, libraries, gui plug-ins, etc.
Edit: This post was originally written with Pd-extended 0.43 in mind. These days there is a nice little plugin called Deken that you can use to easily download and install most of the popular libraries in Pd. It comes bundled with recent versions of Pd-vanilla. You can still use namespaces to load up the objects for most libraries, but for some libraries like zexy that have all the objects bundled into a single file, you will still need to use [declare] to load it up.
Installing libraries and plug-ins isn't so obvious. This guide will hopefully clear up the process, and may even explain more than you need to know.
Recent changes
This first section is mainly for those upgrading to Pd-0.43 from previous versions. If you're new to Pd and are starting on 0.43, you can just skip this section and get on with loading libraries.
It use to be that installing a library was done by putting it wherever you wanted on your system and adding its path to the preferences. While this wasn't particularly difficult, it did have some problems. Recent efforts have been made to standardize this a bit so those problems can be avoided.
In Pd-extended 0.43, you can't add paths from within Pd any more like you used to. You can open the preferences and add a path, but it won't save it. This means that non-default libraries won't load on start-up any more; you have to load them from within the patch. While this sounds like a hassle, it does have the advantage that patches are much easier to share. You don't have to worry about others having different start-up settings than you. It also forces the patch to document what libraries are being used, so if an object isn't loading, you don't have to go on some crazy hunt to find out where it came from or what it's supposed to do.
Putting them in the right folder
To make sure Pd can easily find the library, you need to put them in the right folder. This is OS dependent. The following folders are your options (taken from here). I personally recommend putting them in the user-specific folders since they are likely easier to migrate when updating your OS.
Linux:
User-specific:
~/pd-externals
Global:
/usr/local/lib/pd-externals
Mac OSX
User-specific:
~/Library/Pd
Global:
/Library/Pd
Windows
User-specific:
%AppData%/Pd
Global:
%CommonProgramFiles%/Pd
Linux and OSX are pretty straight-forward. "~" means your home folder.
Windows is a bit trickier. %AppData% and %CommonProgramFiles% are environment variables that contain specific directories. What the exact directory is depends on which version of Windows you are on. You can find out what it is by opening up the command line and typing this:
echo %AppData%
You might end up with something like C:\Users\username\AppData\Roaming or C:\Documentes and Settings\username\Application Data. Also, to see it in the file browser, you might need to show hidden files. At any rate, once you find the directory, create a Pd folder if there isn't one, and put your library, objects, or plug-ins there.
Loading whole libraries
To load a library you have a few options. The one that works on both vanilla and extended is to use [declare -stdpath libraryname]. The libraryname is the name of the folder that all the objects/abstractions are in.
[declare] doesn't always work as expected in abstractions, though. In Pd-extended, you can also use [import], which works well in abstractions. I have found that sometimes it doesn't work with libraries of abstractions that don't have a meta file, though. But that can be fixed by just making one. Simply create an empty Pd patch and save it as libraryname-meta.pd in the library's folder. That's all the meta patch is.
A third option (also Pd-extended only) is to use [path]. This is new to Pd-extended 0.43 and works similarly to [declare]. I haven't needed it, yet. But it's there.
Once the library is loaded, you should be able to load an object or abstraction just by creating it by name.
Loading objects or abstractions using namespaces
While this method means a little more typing, it is also the safest, and it makes it easier to find out what objects are from which library. The way you do it is add the library name (i.e. the namespace) to the beginning of the object when you call it, like this:
[zexy/multiplex~] <-- load the [multiplex~] object from zexy
[cyclone/comb~] <-- load [comb~] from cyclone
You don't have to load the library with [import] or [declare] for this to work. You just call the object that way.
Why is this safest? Because it's possible for different libraries to have objects with the same name. For example, both cyclone and zexy have an object called [mean]. But they don't work exactly the same. zexy's takes a list, while cyclone's takes in a continuous stream. If you have both libraries loaded (and in Pd-extended, these two libraries happen to be loaded by default), you can't be sure which one you're getting if you just type [mean]. However, if you type [cyclone/mean], you know exactly which one you are getting.
PD from Max, missing Umenu
Lurked for a while, first post now.
I've been using Max/MSP pretty heavily since last December, and I've fallen in love with the visual coding paradigm. For a variety of reasons PD appeals to me more than Max (though I did get used to the bells and whistles). I've replaced all my hardware effects (loopers, stompboxes, synths, sequencers) with max patches, and I'd be comfortable enough making the same over again in PD, but I'm having trouble translating a few objects that I relied on heavily in Max.
Umenu is a big one, the ability to receive numbers and output corresponding text comes in handy with scripting lots of objects, and routing sends and receives. It's ease of populating, rewriting, and deleting of entries makes many complex tasks easily manageable. It also functions as a great label when I hid things away. I suspect there's an equivalent method, but nothing leaps out. Should I be looking at some sort of coll type object? Struct?
In the DSP realm, I'm a little worried not to see Rate~ or some analog of it. I use phasor~ to control my loops, and Rate~ works magic on polymetric sequences. I could probably rig up a similar system scaling and wrapping a signal, but straight up Rate would be best.
In order to be able to slot effects in and out of different parts of the signal chain, I've been using combinations of bpatchers and polys, with scripting to switch between different stompbox abstractions. I found the graph on parent option, but it doesn't seem (at least not obviously) that I can use scripting on it to call up different subpatches. Please correct me if I'm wrong.
I think those three might just cover it (at least for the time being). I've found the externals pulled from the max library to be an amazing resource, and between overlapping objects, manuals, and the answers on this forum most of what I need to know is readily available. If those objects lack analogs in PD I may just bite the bullet and get into java/c/python...at the moment I have no experience with text based programming, but I'm just looking for an excuse, really.
I'll be hitting the manuals cover to cover as best I can in the morning, but I'd be glad to have my patches running sooner all the same.
All help is much appreciated.
Aa
Problems or missing understanding with send and receive
hi there,
i just started working with PD for an art project.
and somehow i'm stuck with send and receive.
so reduced from everything special around that's what i want to do:
i have a number box connected to the right inlet of a float (memory) object.
and there is math operation objects ("+2", "+15", ...).
and there's bang object which gets the value stored in the float object.
because i need the the value of the float object several times i connected its outlet with a send-box ("s Xvalue") and everywhere i need the value of the float object i have a receive object ("r Xvalue").
and for the same reason - i need the value of the float objects several times - the bang object is connected with the float object throug send-receive ("s getValue" or "r getValue").
for some reason i don't know after changing value in the number-box then hitting the "getValue" bang, which activates the float memory box, the value hasn't changed. then i hit again and it is changed.
i have the same situation with a couple of number boxes and with some it's no problem with some it is.
and generally: isn't there a easier way to set a variable with a value and have it accessable in the whole programm without send/receive or linking
just as it is in most other programming languages?
thanks for any help
stephan
Conditional gate
@mod said:
But time and time again we see the same sort of posts. People who just want to turn an audio signal on and off use something like [spigot~], people use [counter] instead of basic pd objects. They post these patches and run into trouble that could easily be avoided by only using vanilla objects unless necessary.
What's wrong with [counter]? Objects like those remedy the trouble of trying to figure out how to make one using only vanilla objects. Not that it's particularly difficult to do, but it may just be more intuitive or time saving to someone to use [counter].
Of course most people are using extended, but it's such a vast ocean that no-one knows how EVERY object in extended works. The object in question here, [gate], i can only hazard a guess, but i'm thinking that a maximum of 50% of users know the cyclone library and in particular the [gate] object well enough to debug a patch.
Well, that's where the basic advice that you and others have posted comes in: Right click -> Help.
Besides, I don't really think that because less people know or use an object should deter one from trying it. It may just make more sense or fit with their particular programming preferences. I know I like to build from low-level objects and work up, but not everyone is so interested. For example, I've built my own compressor abstraction. But plenty of other people would rather just load a compressor object and be done with it. Nothing wrong with either approach.
Also, I've been using Pd long enough that I feel comfortable saying I'm in "expert" territory. I don't know what every extended object does, but I don't know what EVERY vanilla object does, either.
(I'm speaking from my own bad experiences here too, because my old patches had some extended objects in them, and i answered countless emails from people having trouble with those externals not loading. I could have saved myself a lot of time by just using the correct vanilla constructs in the first place)
Now, this is a different issue, and I'm more inclined to agree here. You can definitely ensure higher compatibility by sticking to vanilla objects, as some externals don't work correctly on all OS's and vanilla users may not have some of the more popular libraries installed, but it does come with the potential costs of flexibility or computational load. And, this is only an issue if you want to share your patches or use them on other OS's.
When I'm writing a patch that's for personal use only, and I don't expect to be sharing it, I tend to use whatever I want. But if I'm making an abstraction I might share, I usually follow an order of precedence:
1. Use vanilla objects where possible/practical for best compatibility.
2. Use extended objects if needed, since it's used widely and newbie-friendly.
3. If absolutely necessary, use a popular lib not included in Pd-extended, like GridFlow or RjLib (I've never had to do this, yet).
But that's entirely for compatibility reasons only.
@Shakasin said:
But is there something in vanilla that could replace my [gate] just curious ?
. [== 1] [== 2] [== 3]
| | |
[spigot] [spigot] [spigot] etc....
Connect the gate number to the left inlet of the [== ] objects, and the value you want to pass to the left inlet of the [spigot]s.
Visualizing the connection-order!!..
Hey,
I want to build a little "patch-analyser" (in pd since I don't know about "deeper" programming in C and so on). Mainly because I dislike the [trigger]'s & I just want to avoid using them.
It never ever happend that the order of objects being computed suddenly changed without triggers, but triggers slow things down alot. <- Just measure the "[realtime]" of banging e.g. "[until]" 100000 with and without [trigger]'s...
So as far as I can see there "technically" is no need for those triggers.
The order is saved within the save-file!
They just help visualizing the processing-structure! Some people consider using triggers as rather clean which may be true for looking at the patch but not for processing it.
..in short: without trigger's I build patches from right to left (because right inlets are the passive ones most of the time) so that most right objects (the ones you placed first) are computed at first!
It's different with "audio"-data (the vectors). There an object's output only is computed after all inlets have received data... (this makes sense sice each element of one vector can "interact" with each element of another vector & they are connected to the sample-rate)
Anyways, not using triggers but trying to keep a clear visual structure may "uglify" the appearance of the patch sometimes, or just doesn't work (more than one active inlet and so on..)
...Sooo the easiest way to keep the information about the order visualized is "on demand".
Imagine this: You select an object (msg etc.) and its outgoing (and incomming) connections get numbers written next to them according to the order they are processed.
This can be programed in pd itself since pd is capable of creating object's via text (msg) & saves the processing-order with the save-file (hopefully even before)
Next step would be beeing able to change the processing-order just by changing those numbers (helps alot with multiple connections & even [trigger]'s are not comfortable in this situation..) ... but that's far future...
What do you think of this?!
-Or an switchable extra graphical-layer containing those numbers for all objects (at once)... I gonna upload a patch that demonstrates this soon...
Now here comes the important part (still reading?! ):
Does anyone know if and where data (e.g. a pre-savefile) is stored as long as it's not saved???!!! I ask because I managed to analyse the text of save-files somehow, just by reading out the file with some textread-objects in pd... but I don't know where to find data of unsaved patches. (and it's a little annoying to save your patch every time just to analyse the connection-order)
Aaand is there a method to identify a selected object?? (For now I use a unique message that is sent to the object I want to "select" and then trace that connection in the save-file)
Actually I found something like this (just have to look where that was..), but actually it didn't work since it was made for earlier versions and it had to change some pd-dll's (yep -Windows..).
As usual don't hesitate to correct me if I'm wrong.
And please respond even if you just like or dislike this idea...
Bye Flipp