"Return to caller" (followup from "symbols explicit")
@oid said:
Edit2: I guess wires are also gotos then.
I realized a bit later what the difference is -- In Pd, wires are procedure calls, not gotos.
Continuing the tangent, feel free to disregard
Pascal distinguishes between procedures and functions, where a function has a return value and a procedure does not. (C gets rid of the term "procedure," but you can still have void
functions.) In SmallTalk (and SC inherits this), there is always a return value, which may be ignored -- hence no such thing as a procedure. The last thing a function or method does is to return a result and drop its own execution frame off the stack. In rand(20) * 2
, after rand
returns the random number, there is only the result -- the fact that rand
was called at all is forgotten. (Returning from a procedure just drops the execution frame, with no return value.)
In dataflow, there are only procedures and the last thing an object does is to procedure-call the next object -- the entire history stays on the stack. In [random 20] --> [* 2] --> [print]
, "random" is more like: 1. Get from the RNG; 2. Call descendants with this result; 3. Then backtrack up the stack.
It's kind of like, Random(20, descendants: [Multiply(_, 2, descendants: [Print(_)])])
. I could hypothetically create these objects in SC and it would work (but, not much point lol).
The two approaches are mirror images: lisp would write (print (* (random 20) 2))
where the last operation to be performed ("print") is at the head of the tree. Structurally SC is the same. Syntactically it may be different, since a method selector may be either pre- or post-fixed, but (rand(20) * 2).postln
still parses as follows. Then it renders bytecodes depth first! So internally it ends up like FORTH ("push 20, random, push 2, *
, postln").
postln
|
*
/ \
rand 2
|
20
But in Pd, the last operation is structurally the innermost leaf, not the head.
I think this explains a bit why it took me a good couple of years to wrap my head around dataflow, even though (I thought) I knew a thing or two. It's literally upside-down world for me. Still struggle with that sometimes.
hjh
Keyboard HID vs serial comport for Sensor values on pico
I'm trying to get values from analog sensors connected to a raspberry pi pico. That pico is plugged into a rp5 where I want to read those sensor values in Pure Data. Question-- to interface the pico's sensor values with the Pure Data I can either
Use the pico as a keyboard HID device (using MicroPython on the pico, and "HID" object in Pure Data), or
Use the "comport" object in pure data to unpack and read the sensor values over serial.
Does anyone have any thoughts about either way? Limitations or resolution(if that even applies). Someone please correct any of this- I'm thinking the HID might be a bit friendlier, both pi's and an audio interface are going in a Disney princess guitar I got from goodwill eventually, but I'm trying to get it functional first. I see values in pure data using a Logitech USB game controller and the "HID" object, and about 10 years ago I got sensor values over serial with the "comport" object in Pure Data with an Arduino Nano v3.1. I was reading a little about the u2if git repository that might be another option...and Just found out about the teensy boards... was thinking the teenzy 4.0 might be a better option. But- I haven't gotten this working, so that's first. I appreciate this space!
using HID object on Raspberry Pi
as an update to this: it's definitely because the [hid] object that is in Deken for macOS is not the same [hid] object that is on the Raspbian repo. It's confusing! I was able to make it work by copying some old screenshots I found of the old [hid] object, and having two different versions of the patch with [hid] object in action.
using HID object on Raspberry Pi
sorry for the double forum post, just starting a new thread for clarity.
I'm trying to use a USB joystick with pure data on my headless Raspberry Pi. I've got the patch working on my laptop just fine.
I've installed the pd-hid external on my Raspberry Pi, but the joystick doesn't do anything in the patch. The external loads when I start up Pd, but I don't get any input information from the joystick into Pd.
One theory I have is that the version of [hid] is different on the Raspberry Pi repo vs. Deken? On Raspberry Pi it is says:
[hid] 0.7, written by Hans-Christoph Steiner <hans@eds.org>
compiled for Debian on 2022/12/07 at 09:43:35 UTC```
Whereas the version on Deken is "hidv0.1.0.dek".
Could these be different? Or is there something else entirely that I'm missing?
HID object on Raspberry Pi?
Has anyone managed to get an HID object working on Raspberry Pi? I've tried compiling this one but haven't succeeded yet. This is the error I'm getting:
/usr/bin/ld: cannot find -lusbhid_map: No such file or directory
collect2: error: ld returned 1 exit status
make[1]: *** [/home/pi/hid-pd-external/deps/pd-lib-builder/Makefile.pdlibbuilder:885: hid.pd_linux] Error 1
make[1]: Leaving directory '/home/pi/hid-pd-external/src/hid'
make: *** [Makefile.linux:20: all] Error 2```
I have installed libhidapi and libusb as described in the Readme, so I'm a bit confused.
It's in Deken on macOS and works great, I'd love to get it working on a Pi, if anyone has any tips!
ofelia on raspberry pi?
Hi,
I am trying to get ofelia to run on a couple of rpi. Right now I am trying a rpi 3B+ running https://blokas.io/patchbox-os/
I run ofeila with the ofelia-fast-prototyping abs on my mac successfully.
Following install instructions here https://github.com/cuinjune/Ofelia
after running
sudo ./install_dependencies.sh
it ends like this:
detected Raspberry Pi
installing gstreamer omx
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
gstreamer1.0-omx is already the newest version (1.0.0.1-0+rpi12+jessiepmg).
The following package was automatically installed and is no longer required:
raspinfo
Use 'sudo apt autoremove' to remove it.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Updating ofxOpenCV to use openCV4
sed: can't read /home/patch/Documents/Pd/externals/addons/ofxOpenCv/addon_config.mk: No such file or directory
sed: can't read /home/patch/Documents/Pd/externals/addons/ofxOpenCv/addon_config.mk: No such file or directory
When running the example patches in Pd I get this in PD console:
opened alsa MIDI client 130 in:1 out:1
JACK: cannot connect input ports system:midi_capture_1 -> pure_data:input_2
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia d $0-of
... couldn't create
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia d $0-of
... couldn't create
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia d $0-of
... couldn't create
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia d $0-of
... couldn't create
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia d $0-of
... couldn't create
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia f ;
ofBackground(20) ;
ofSetSmoothLighting(true) ;
ofSetSphereResolution(24) ;
local width , height = ofGetWidth() * 0.12 , ofGetHeight() * 0.12 ;
sphere = ofSpherePrimitive() ;
sphere:setRadius(width) ;
icoSphere = ofIcoSpherePrimitive() ;
icoSphere:setRadius(width) ;
plane = ofPlanePrimitive() ;
plane:set(width * 1.5 , height * 1.5) ;
cylinder = ofCylinderPrimitive() ;
cylinder:set(width * 0.7 , height * 2.2) ;
cone = ofConePrimitive() ;
cone:set(width * 0.75 , height * 2.2) ;
box = ofBoxPrimitive() ;
box:set(width * 1.25) ;
local screenWidth , screenHeight = ofGetWidth() , ofGetHeight() ;
plane:setPosition(screenWidth * 0.2 , screenHeight * 0.25 , 0) ;
box:setPosition(screenWidth * 0.5 , screenHeight * 0.25 , 0) ;
sphere:setPosition(screenWidth * 0.8 , screenHeight * 0.25 , 0) ;
icoSphere:setPosition(screenWidth * 0.2 , screenHeight * 0.75 , 0) ;
cylinder:setPosition(screenWidth * 0.5 , screenHeight * 0.75 , 0) ;
cone:setPosition(screenWidth * 0.8 , screenHeight * 0.75 , 0) ;
pointLight = ofLight() ;
pointLight:setPointLight() ;
pointLight:setDiffuseColor(ofFloatColor(0.85 , 0.85 , 0.55)) ;
pointLight:setSpecularColor(ofFloatColor(1 , 1 , 1)) ;
pointLight2 = ofLight() ;
pointLight2:setPointLight() ;
pointLight2:setDiffuseColor(ofFloatColor(238 / 255 , 57 / 255 , 135 / 255)) ;
pointLight2:setSpecularColor(ofFloatColor(0.8 , 0.8 , 0.9)) ;
pointLight3 = ofLight() ;
pointLight3:setPointLight() ;
pointLight3:setDiffuseColor(ofFloatColor(19 / 255 , 94 / 255 , 77 / 255)) ;
pointLight3:setSpecularColor(ofFloatColor(18 / 255 , 150 / 255 , 135 / 255)) ;
material = ofMaterial() ;
material:setShininess(120) ;
material:setSpecularColor(ofFloatColor(1 , 1 , 1)) ;
... couldn't create
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia f ;
pointLight = nil ;
pointLight2 = nil ;
pointLight3 = nil ;
collectgarbage() ;
... couldn't create
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia f ;
local width , height , time = ofGetWidth() , ofGetHeight() , ofGetElapsedTimef() ;
pointLight:setPosition((width * 0.5) + math.cos(time * 0.5) * (width * 0.3) , height / 2 , 500) ;
pointLight2:setPosition((width * 0.5) + math.cos(time * 0.15) * (width * 0.3) , height * 0.5 + math.sin(time * 0.7) * height , -300) ;
pointLight3:setPosition(math.cos(time * 1.5) * width * 0.5 , math.sin(time * 1.5) * width * 0.5 , math.cos(time * 0.2) * width) ;
... couldn't create
/home/patch/Documents/Pd/externals/ofelia/ofelia.l_arm: libboost_filesystem.so.1.67.0: cannot open shared object file: No such file or directory
ofelia f ;
local spinX = math.sin(ofGetElapsedTimef() * 0.35) ;
local spinY = math.cos(ofGetElapsedTimef() * 0.075) ;
ofEnableDepthTest() ;
ofEnableLighting() ;
pointLight:enable() ;
pointLight2:enable() ;
pointLight3:enable() ;
material:beginMaterial() ;
plane:rotateDeg(spinX , 1 , 0 , 0) ;
plane:rotateDeg(spinY , 0 , 1 , 0) ;
plane:draw() ;
box:rotateDeg(spinX , 1 , 0 , 0) ;
box:rotateDeg(spinY , 0 , 1 , 0) ;
box:draw() ;
sphere:rotateDeg(spinX , 1 , 0 , 0) ;
sphere:rotateDeg(spinY , 0 , 1 , 0) ;
sphere:draw() ;
icoSphere:rotateDeg(spinX , 1 , 0 , 0) ;
icoSphere:rotateDeg(spinY , 0 , 1 , 0) ;
icoSphere:draw() ;
cylinder:rotateDeg(spinX , 1 , 0 , 0) ;
cylinder:rotateDeg(spinY , 0 , 1 , 0) ;
cylinder:draw() ;
cone:rotateDeg(spinX , 1 , 0 , 0) ;
cone:rotateDeg(spinY , 0 , 1 , 0) ;
cone:draw() ;
material:endMaterial() ;
ofDisableLighting() ;
ofDisableDepthTest() ;
... couldn't create
Thankful for help!
Help with audio patch on off based on some condition
@jameslo said:
I really wish Pd was at least this regular--it would've been much easier for me to learn. [timer] is a counter example.
AFAICS [timer] does not break the rule about one input to a hot inlet producing one output.
It does put the hot inlet on the right -- agreed that this is a strange decision. Probably the only reason for that is that it's very common to request a value from the timer and immediately reset it. If the hot inlet were on the left, you would have to cross the wires coming out of the preceding [t b b]. So it's a bit prettier at the expense of regularity (kind of like irregular verbs).
But I didn't say anything about the position of the hot inlet -- only that the hot inlet, wherever it is, produces one output for one input. Admittedly I haven't been around Pd as long as some members here, but the only exceptions I'm aware of are [spigot] (where the user can explicitly disable output), and method calls sent to hot inlets (which may not produce output, e.g. set xxx
).
hjh
Circular buffer issues
@jameslo said:
Honestly, I didn't know if that was @fintg's requirement,
It's certainly a reasonable guess. If the requirement instead were "I just played something cool; write the last 10 seconds to disk" you can do that without a circular buffer at all.
I was just surprised and annoyed that one can only access the delay line's internal buffer at audio rate (and was hoping that someone would prove me wrong).
Access to the internal buffer wouldn't be very useful without also knowing the record-head position. In that case delwrite~ would need an outlet for the current frame being written.
That would actually be a very nice feature request.
In SuperCollider as well, DelayN, DelayL and DelayC don't give you access to the internal buffer. But you can create your own buffer and write into it, with total control over phase, with BufWr -- and, because you control the write phase, you already know what it is. It's quite nice way to do it.
Basically the lack of ipoke~ in vanilla causes some headaches.
Look at the hoops I have to jump through! The extra memory I have to use!
I don't think there is any way to do this without using some extra memory.
In a circular buffer, you have:
|~~~~~~ new audio ~~~~~~|~~~~~~ old audio ~~~~~~|
^ record head
When you write to disk, naturally you want the old audio earlier in the file. There are only two ways to do that. One is to write the "old" chunk without closing the file, and append the "new" chunk, and then close the file.
In SC, if I know the record head position, I'd do it like:
buf.write(path, "wav", "int24", startFrame: recHead, leaveOpen: true, completionMessage: { |buf|
buf.writeMsg(path, "wav", "int24", numFrames: recHead, startFrame: 0, leaveOpen: false)
});
AFAICS Pd does not support this, so you're left with duplicating new after old data. (FWIW, though, there's plenty of memory in modern computers; I wouldn't lose sleep over this.)
Then there is the problem of synchronous vs asynchronous disk access. AFAICS Pd's disk access is synchronous, and because the control layer is triggered from the audio loop, slow disk access could cause audio dropouts. OS file system caching might reduce the risk of that, but you never know. Ross Bencina's article about real-time audio performance advises against time-unbounded operations in the audio thread.
SC's buffer read/write commands run in a lower priority thread; wrt audio, they are asynchronous. This is good for audio stability, but it means that, by the time you get around to writing, the record head has moved forward. So, even though I could do the two-part write easily, I'd get a few ms of new data at the start of the file. I think I would solve that by allocating an extra, say, 2 seconds and then just don't write the 2 seconds after the sampled-held recHead value: startFrame: recHead + (s.sampleRate * 2)
. (If it takes 2 seconds to write a 10 second audio file, then you have bigger problems than circular buffers.) Then the record head can move freely into that zone without affecting audio written to disk.
hjh
No sound. Failed install?
HI,
a newbie, I am trying to install and use Pd 0.53.0 on a Fedora 35 machine.
I think I installed (from source) fine, but I do not get any sound.
I am not sure what I am supposed to check and do.
Some info on my install below.
Thanks for your help.
Below, I doubt line audio APIs: PortAudio ALSA OSS
is how it should be, but I am not sure how to fix.
pd 0.53.0 is now configured
Platform: Linux
Debug build: no
Universal build: no
Localizations: yes
Source directory: .
Installation prefix: /usr/local
Compiler: gcc
CPPFLAGS: -DNDEBUG
CFLAGS: -ffast-math -fno-finite-math-only -funroll-loops -fomit-frame-pointer -O3 -g -O2
LDFLAGS:
INCLUDES:
LIBS: -lpthread -ldl
External extension: pd_linux
External CFLAGS: -fPIC
External LDFLAGS: -Wl,--export-dynamic -fPIC
fftw: no
wish(tcl/tk): wish
audio APIs: PortAudio ALSA OSS
midi APIs: ALSA OSS
libpd: no
$ ./pd -listdev
audio input devices:
0. USB Device 0x46d:0x825 (hardware)
1. USB Device 0x46d:0x825 (plug-in)
2. HDA Intel PCH (hardware)
3. HDA Intel PCH (plug-in)
4. HDA NVidia (hardware)
5. HDA NVidia (plug-in)
6. Trust PC Headset (hardware)
7. Trust PC Headset (plug-in)
audio output devices:
0. USB Device 0x46d:0x825 (hardware)
1. USB Device 0x46d:0x825 (plug-in)
2. HDA Intel PCH (hardware)
3. HDA Intel PCH (plug-in)
4. HDA NVidia (hardware)
5. HDA NVidia (plug-in)
6. Trust PC Headset (hardware)
7. Trust PC Headset (plug-in)
API number 1
MIDI input devices:
1. ALSA MIDI device #1
MIDI output devices:
1. ALSA MIDI device #1
priority 94 scheduling failed.```
If I try to set to something different from HDA Intel, I get
ALSA input error (snd_pcm_open): Device or resource busy
ALSA output error (snd_pcm_open): No such file or directory
`
plot-graph - a way to display waveforms
Here I've uploaded plot graph as an abstraction plus two other abstractions to assist in its usage make-plot and cursor-drive
plot-graph creation: plot-graph unique-name size-x size-y;
Address the settings with messages to in-unique-name (eg [s in-$0-channel-L] or connect a control-rate wire to top left corner;
make-plot creation: make-plot array-name plot-resolution;
eg [make-plot $0-left-channel 200]
make-plot is used to take the audio file size given by soundfiler and divide that by the x resolution of the plot-graph window, read the array in chunks of the min max amplitudes to plot the waveform.
cursor-drive creation: [cursor-drive x resolution] eg [cursor-drive 200] drives the play cursor if active
For best results I found it best to keep the resolution to half the window size, say 200 window 100 resolution
SETTINGS. for plot-graph
size float float (can be set as a creation arg);
min float (y value <= 0 for peaks -1 to 0);
max float (y values>= 0 for peaks 0 to 1);
index float (x value 0 to resolution cur float (x position for cursor 0 to resolution);
cur-vis float (hide/show cursor 0 or 1);
min-vis float (hide/show min plot 0 or 1);
max-vis float (hide/show max plot 0 or 1);
colour float float float float float float;
where:-;
float 1 = back colour (0 to 999 struct colours);
float 2 = border colour (0 to 999 struct colours);
float 3 = plot colour (0 to 999 struct colours);
float 4 = cursor colour (0 to 999 struct colours);
float 5 = plot thickness (1 to 5ish);
float 6 = border thickness (0 to 30ish);
plot-fill float (hide/show fill 0 or 1)
fill-col float float (0 to 999 thickness 0 to 5)
For an animated plot with fill try the following in the plot-graph-help
load audio file
click 100 resolution
click look here for more
scale x using the number-box to 200
toggle off min-vis and cursor-vis
click play (and loop if a small file)
in the more page
toggle scope plot
toggle fill plot
adjust normalise
play with the colours
plot-graph.pd and plot-graph-help.pd are read only to prevent overwriting the defaults, change this if you wish
Have fun
Cheers
Balwyn
plot-graph.zip
The picture is reduced to 70%