Four month installation using PD on Pi4 and Arduino via serial
I have an installation using pd and some sensor that I'm getting the data from Arduino to pd via serial.
The installation should run for 4 month without stop.
How can I make sure pd is always on? As well as the Pi4 ?
Does the cable of the serial make difference? or If the cable I'm using is working now I can be sure it will work?
Thanks
espd - tutorial
Hi all!
I had some time during vacations and I wanted to try running Miller's espd version. Here's a small tutorial.
The development board I bought: ESP32-LyraT > Mouser | Aliexpress
INSTALL ESP-IDF (IoT development framework)
mkdir ~/esp && cd ~/esp
git clone -b v4.4.2 --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.sh esp32
INSTALL ESP-ADF (audio development kit)
cd ~/esp && git clone --recursive https://github.com/espressif/esp-adf.git
SETUP ENV VAR
export ADF_PATH=~/esp/esp-adf && . ~/esp/esp-idf/export.sh
ESPD
download espd: http://msp.ucsd.edu/ideas/espd/
cd espd
git clone https://github.com/pure-data/pure-data.git pd
cd pd
git checkout 05bf346fa32510fd191fe77de24b3ea1c481f5ff
git apply ../patches/*.patch
Edit main/espd.h put your wifi credentials and the IP of the computer that will control espd:
#define CONFIG_ESP_WIFI_SSID "..."
#define CONFIG_ESP_WIFI_PASSWORD "..."
#define CONFIG_ESP_WIFI_SENDADDR "...."
mv sdkconfig.lyrat sdkconfig
idf.py build
idf.py -p /dev/ttyUSB0 flash (hold boot and then press reset on lyrat)
idf.py -p /dev/ttyUSB0 monitor (Ctrl+] to exit)
HOST
- open pd installed on (SENDADDR)
- open test-patch/host-patch.pd
If connected this message (ESPD: sendtcp: waiting for socket) will stop and you will see the mac address in the host patch.
1- click on [send pf begin-new poodle .<
2- click on [line 0, auto< to send the defined patch (esp-patch.pd)
3 - click [send pd end-new<
4 - connect headphone, play with [send f 440< and [send f 660<
Custom patch:
- Use mono [dac~ 1] only
- Add this to your patch:
- in host-patch.pd change [read your-patch< -> [text define patch] redo step 1 to 3
TODO
Would love to play more with the code, right now I am not able to load complex vanilla patch. Also using the AUX (or built-in microphone) would be awesome (but I'm wondering about the round-trip latency (would it be under 15ms)).
How to make the outlet port "hot area" a bit larger?
@ddw_music said:
Does anyone know offhand where to hack the hot zone size, so that maybe one does not have to have superhuman precision?
searching sources for
mouse
I found in https://github.com/pure-data/pure-data/blob/20334410c20948f14f5c1d8ae5ed992717b83291/tcl/pd-gui.tcl
# mouse cursors for all the different modes
[...]
set ::cursor_editmode_connect "circle"
.
Then searching for
cursor_editmode_connect
I found probably relevant
https://github.com/pure-data/pure-data/blob/c4ae1bd8df436de15c0a80f303ae33b5f3569088/src/g_editor.c
/* look for an outlet */
else if (hitobj && (noutlet = obj_noutlets(hitobj)) &&
ypos >= y2 - (OHEIGHT*x->gl_zoom) + x->gl_zoom)
{
int width = x2 - x1;
int iow = IOWIDTH * x->gl_zoom;
int nout1 = (noutlet > 1 ? noutlet - 1 : 1);
int closest = ((xpos-x1) * (nout1) + width/2)/width;
int hotspot = x1 +
(width - iow) * closest / (nout1);
if (closest < noutlet &&
xpos >= (hotspot - x->gl_zoom) &&
xpos <= hotspot + (iow + x->gl_zoom))
{
if (doit)
{
[...]
/* not in an outlet; select and move */
...Searching the sources for IOWITH
or better OHEIGHT
has this result among others:
https://github.com/pure-data/pure-data/blob/5462d1eae0ad9f139997d56d459c212e797d96be/src/g_canvas.h
* --------------------- geometry ---------------------------- */
#define IOWIDTH 7 /* width of an inlet/outlet in pixels */
#define IHEIGHT 3 /* height of an inlet in pixels */
#define OHEIGHT 3 /* height of an outlet in pixels */
#define IOMIDDLE ((IOWIDTH-1)/2)
#define GLIST_DEFGRAPHWIDTH 200
#define GLIST_DEFGRAPHHEIGHT 140
#define GLIST_DEFCANVASXLOC 0
#ifdef __APPLE__
#define GLIST_DEFCANVASYLOC 22
#else
#define GLIST_DEFCANVASYLOC 50
#endif
.
(Not sure how the apparently different size of inlets and outlets hot area is coded? Inlets appear to be 'magnetic'. )
Wish there was a shortcut to open objects-help.
Could belong here:
https://github.com/pure-data/pure-data/blob/90ad8005199605095e49dbbf1daf4f032211b7f4/tcl/pd_bindings.tcl
Wet-Dry Mix In Amplitude Modulation
Couldn't resist playing with this a little more.
This patch demonstrates the double-speed problem. Ring modulator math requires multiplying by a negative sometimes, but of course we don't perceive a negative amplitude. The amplitude we perceive will be the absolute value of the modulator.
To make a smooth transition from an unmodulated signal, I'm using the formula (mod - 1) * mod_amount + 1
:
- If mod_amount is 0, then the modulator ranges +1 to +1 = no modulation.
- If mod_amount is 1, then the modulator ranges -1 to +1 = full modulation.
When mod_amount > 0.5, then there is a negative lobe in the modulator, which folds over to positive in our perception. It's this wave-folding function that causes the doubling in speed (as gn said).
(The audio source in this patch uses https://github.com/jamshark70/hjh-abs and [sf-play~] in turn depends on cyclone. You can substitute any other audio source.)
I don't have a really good workaround for that. As an experiment, I tried cross fading between a full speed modulator and half speed (substitute this subpatch in place of the [osc~]). It sounds a little awkward (and you should take care that the LFOs stay in phase -- otherwise the linear cross fade will drop 3 dB in the middle).
I'm afraid I don't have a better solution -- just, maybe this sheds more light on it.
hjh
Can I assign an ID number to a patch on Pure Data?
@kobe No.
If the patches are on the same computer running in the same instance of Pd then simple [send !D1] and [receive ID1] will work.
But once a router is involved it needs an IP address and port to know where to send the data.
However, all computers on your network register their names in local dns master browser and the IP address can be looked up......... much like "localhost" is translated to 127.0.0.1 or "Google" when looked up by your browser on a web DNS server is 142.250.74.195.
DNS allows IP addresses to change...... while your "name" search will always land (once theDNS servers are updated).
So you should be able to use [connect raspberrypi3 3000( if your other computers name is raspberrypi3
That computer would then make the connection to a patch...... running on that computer...... running a receiver (like netreceive or udpreceive~) set to port 3000
If none of your computers are running a master browser...... or every computer is not running Apple Bonjour....... then it will probably fail.
If you have a number of patches on that receiving computer then they should use different ports.
So if you want to differentiate receiving patches use different ports...... 3001 3002 etc.
And of course if the patches are the same (abstractions) use a $ argument...... i.e.
[mypatch 3001] and [mypatch 3002] where inside you use [udpreceive~ $1].
David.
banging [switch~] performs audio computations offline!
According to block~ help, if you bang [switch~] it runs one block of DSP computations, which is useful for performing computations that are more easily expressed as audio processing. Something I read (which I can't find now) left me with the impression that it runs faster than normal audio computations, i.e. as if it were in control domain. Here are some tests that confirm it, I think: switch~ bang how fast.pd
The key to this test is that all of the bangs sequenced by [t b b b b] run in the same gap between audio block computations. When [switch~] is banged, [osc~] fills array1, but you can see that element 63 of array1 changes after [switch~] is banged. Furthermore, no logical time has elapsed. So it appears that one block of audio processing has occurred between normal audio blocks. [bang~] outputs when that accelerated audio block processing is complete.
This next test takes things further and bangs [switch~] 10 times at control rate. Still, no logical time elapses, and [bang~] only outputs when all 10 bangs of [switch~] are complete. [rzero_rev~ 0] is just an arcane way of delaying by one sample, so this patch rotates the contents of array1 10 samples to the right. switch~ bang how fast2.pd
(There are better ways to rotate a table than this, but I just needed something to test with. Plus I never pass up a chance to use [rzero_rev~ 0] )
Finally, I've seen some code that sends a 1 to [switch~] and then sends 0 after one block of processing. In this test you can see that one block of audio is processed in one block of logical time, i.e. the normal way. switch~ bang how fast3.pd
But that second test suggests how you could embed arbitrary offline audio processing in a patch that's not being run with Pd's -batch flag or fast-forwarded with the fast-forward message introduced in Pd 0.51-1. Maybe it's an answer to two questions I've seen posted here: Offline analysis on a song and Insant pitch shift. Here's a patch that writes 20s of 440 Hz to a file as fast as possible (adapted from @solipp's patch for the first topic). You just compute how many blocks you need and bang away. write440File.zip
Here's another that computes the real FFT of an audio file as fast as possible: loadFFT.zip
But as with any control rate processing, if you try to do too much this way, Pd will fall behind in normal audio processing and stutter (e.g. listen to the output while running that last patch on a >1 minute file). So no free lunch, just a little subsidy.
[expr] logic problem – why is it doing this?
So, I'm working on a patch that is supposed to trigger a sound file to play on the hour and on the half between a specific start and end time.
I'm getting the time using zexy's [time] object. I'm then feed that into an [expr] object that's performing some basic logic to determine if the current time is between the specified start hour and end hour for playback, and either at the beginning of the hour or the beginning of the half hour, and the seconds are equal to zero. If all these conditions are true, the [expr] object outputs a 1, which then triggers the soundfile to play.
This expression looks like this:
expr if(($f1 >= $f4 && $f1 <= $f5) && ($f2 == 30 || $f2 == 0) && ($f3 == 0), 1, $f1)
where:
$f1 is the current hour
$f2 is the current minute
$f3 is the current second
$f4 is the start hour (this is currently set to 12 – i.e. noon)
$f5 is the end hour (currently set at 18 – i.e. 6pm)
It works perfectly. However, if $f1, $f2, $f3 are values like 1, 29, 32 (that's 01:29:32 in 24 hour time), the [expr] gives me true when it should be false! 01:29:32 is not within the specified start or end hour for playback.
I can't figure this out at the moment. I'm wondering if someone can help point out what dumb mistake I'm probably making.
Thanks
Game of Life - new attempt
here is a completely different attempt: the game of life runs on a glsl shader.
i played with that before, but i think know i understood how to customize the shader and also change the rules. it is surprisingly fast, i cannot imagine that the hashlife algorithm can be faster.
https://nullprogram.com/blog/2014/06/10/ this blog was really helpful...
a few drawbacks are that the grid is not borderless anymore (not sure how to change that in the shader),
and that it is only possible to save/copy/paste patterns that are created with mouse clicks...
and it seems difficult to grab the data from the shader for sequencing tones for example...
here is the patch: gol_shader_v001.zip
https://github.com/Jonathhhan/PDGameofLife-shaderVersion-
this is the fragment shader:
uniform sampler2D Tex0;
uniform vec2 resolution;
uniform int lCell_1;
uniform int lCell_2;
uniform int lCell_3;
uniform int lCell_4;
uniform int lCell_5;
uniform int lCell_6;
uniform int lCell_7;
uniform int lCell_8;
uniform int dCell_1;
uniform int dCell_2;
uniform int dCell_3;
uniform int dCell_4;
uniform int dCell_5;
uniform int dCell_6;
uniform int dCell_7;
uniform int dCell_8;
int get(int x, int y) {
return int(texture2D(Tex0, (gl_FragCoord.xy + vec2(x, y)) / resolution).r);
}
void main() {
int sum = get(-1, -1) +
get(-1, 0) +
get(-1, 1) +
get( 0, -1) +
get( 0, 1) +
get( 1, -1) +
get( 1, 0) +
get( 1, 1);
int state = get(0, 0);
if (sum == lCell_1 && state == 0 ||
sum == lCell_2 && state == 0 ||
sum == lCell_3 && state == 0 ||
sum == lCell_4 && state == 0 ||
sum == lCell_5 && state == 0 ||
sum == lCell_6 && state == 0 ||
sum == lCell_7 && state == 0 ||
sum == lCell_8 && state == 0) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else if (sum == dCell_1 && state == 1 ||
sum == dCell_2 && state == 1 ||
sum == dCell_3 && state == 1 ||
sum == dCell_4 && state == 1 ||
sum == dCell_5 && state == 1 ||
sum == dCell_6 && state == 1 ||
sum == dCell_7 && state == 1 ||
sum == dCell_8 && state == 1 ) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
}
also useful as a visual noise generator
Querying whether an array exists or not
you'd be amazed how creative they can be at messing it up
In fairness to your students, due to a historical accident soundfiler's interface is poor. You get a bunch of anonymous values in a single message out the right inlet, and a single value out of the left inlet. For the right outlet it's the user's job to remember the map of attributes to positional arguments and then parse the message to get the positional arguments they care about.
Nobody would ever design the interface that way on purpose. You'd simply send an object to the outlet, like this:
[soundfiler]
|
[get samples type rate etc.]
Now the data would be self-documenting and automatically routed to the appropriate outlet of [get]
. (Ignoring for the moment that args and outlets don't line up on objects like [route]
and [get]
.) Also, the interface would be backwards-compatible since adding a new key/value pair doesn't break anything.
However, there would still two problems doing it this way. First, [get]
also suffers from an annoying historical accident-- it's first arg is the name of the struct. So you have to add an annoying "-" to stand in for null: [get - samples type rate etc.]
Second, the interface in C for dealing with dictionaries in Pd is even worse than the output interface of [soundfiler]
. You can't simply call a function to map a few names to argv data. AFAICT you'd have to define a template, instantiate a scalar, and then manually populate the scalar with the data you want to map. That's too much work just to put names to data, so nobody does it.
There are enough of these problems in the core that when I find myself getting tired of programming in Pd, I'm usually in the middle of doing something low-effort or trivial, like grabbing a value from the middle of a list, or preparing a value downstream for a conditional test. In Javascript or C, I almost always stop due to a mental model of an algorithm not being fully fleshed out, or faulty. (Well, with js there's also stopping due to DOM complexity/edge cases which can be annoying.)
Edit: clarification