how do YOU make a "light" waveform display?
@Load074 Over the past few years I've also been trying out various approaches along the lines of what you're looking for, and actually tried something rather similar to your idea: pulling only one sample per x samples of the source array and sending to a smaller display array. And indeed, it doesn't work because those values are just scattered snapshots of the signal & will be discontinuous with the neighboring display samples. I realized that some kind of averaging would be needed, started to work on it, then got sidetracked & never followed through...
But, I ended up finding two pre-baked solutions:
rh_wavedisplay from netpd
pp.waveform from AudioLab
I can't quite wrap my head around how rh_wavedisplay works from looking inside the abstraction, but the result looks nice. From the help patch:
This abstraction finds the minima and maxima for each section of the source table that covers one pixel of the display array. The result is a good looking waveform that does not suffer from aliasing.
I also like that it allows for only a section of the source array to be used for display (which is important for how my performance patch uses arrays). In practice it still causes audio dropouts when updating large source arrays, unfortunately.
pp.waveform uses data structures, which is why the result looks so different visually. I don't understand data structures enough to play around with this or try to adapt it for my uses, but I would be definitely curious about whether it's any more efficient than those other graphical array manipulation methods.
I also wonder if there's simply no method that will prevent audio dropouts without some kind of array manipulation that can run on a different thread. I've been looking into the shmem library to see if it's possible to outsource the array processing to another Pd instance (similar to the Pd~ approach that @alexandros suggested), haven't gotten very far so I still don't know if there will be a bottleneck when dumping a huge array to memory.
cannot dynamically load position-independant executable
idk that much about c++, but I'm pretty sure there shouldn't be a 'main' function. In pd you compile objects as libraries. You have to look at the 'how to program externals' book. https://github.com/pure-data/externals-howto#definitions-and-prerequisites
Plus I'm pretty sure you have to export stuff correctly (as 'c') so that the object loader knows how to load it
you might try the 'flext' framework or look at the ceammc distribution (I think they might use c++?
https://github.com/grrrr/flext
https://github.com/uliss/pure-data/blob/ceammc/ceammc/ext/class-wrapper/README.md
https://github.com/uliss/pure-data/blob/ceammc/ceammc/ext/src/lib
Also it would be helpful to post the command you're using to compile it
understanding a simple feedback oscillator
@manuels The Computer Music Tutorial by Curtis Roads has a section on feedback FM it might have some answers. Can't seem to figure out how to get google books to link to the section so here is the search, click on page 244.
Edit: Looks like my link actually worked? or is google being "smart" and relying on my history?
space_echo alteration...
Hi @whale-av. Thank you for this patch.
I am having a few issues with it. I am getting an error "inlet: expected float but got bang"
I think the issues is In the pd control start/stop section. In that section I disconnected the [s phase_reset] from the 2nd outlet of the trigger and connected it to the first outlet of the trigger so it could get a float. I don't know if that stopped other things from working.
Also, in that same start/stop section I can't get the "control" array to change sizes when I press the start or stop button. Would it make sense to have a timer in that box and have the array use the time from the timer to resize the array?
Thank you for the patch!
DIY polyphonic modular synth
Hello,
Following my last post in output~ section, here is a brand new website dedicated to my DIY polyphonic modular synth: https://www.heritagesynthesizers.fr/
In the "Technical informations" section you will find a slideware with an overview of the architecture and the different components. Pure Data is the core of this hardware modular synth with early 1970s look and feel.
This project has started in July 2020 and is not yet finalized, but is already producing interesting sounds!
Frederic.
Send .syx file
@whale-av said:
@lo94 [midiout] requires decimal....... and a sysex file will be in Hex (almost certainly)....... https://forum.pdpatchrepo.info/topic/377/sysex/32
Well... maybe.
For instance, https://mido.readthedocs.io/en/latest/syx.html has a section for "SYX files -- reading and writing," and another section for "Plain Text Format" sysex files. So, apparently, there are two ways that sysex could be written to disk -- a sequence of bytes (numeric), or as text, where each byte has been encoded as two hex digits.
"read_syx_file() determines which format the file is by looking at the first byte. It raises ValueError if file is plain text and byte is not a 2-digit hex number."
Sysex messages are supposed to be introduced by a byte F0, and terminated by F7. So you could do as this site suggests -- read one byte, and if it == 240, then treat it as a byte stream.
I have no idea whether binary or hex-coded sysex dumps are more common in the wild, only that at least one reference page implies that both exist.
It is possible that a whole sysex dump can be passed in one message (still decimal though) to [midiout], but I have no means for testing that.
I just tested this by having SuperCollider print out sysex messages -- that is, there is no need to have a MIDI device receive sysex.
MIDIClient.init;
// '5' is Pd's MIDI source in the device list
// may vary in your system
MIDIIn.connect(0, 5);
MIDIdef.sysex(\y, { |... args| args.postln });
[240 1 2 3 4 247( --> [midiout]
then caused SC to print: [ Int8Array[ -16, 1, 2, 3, 4, -9 ], 8454145 ]
= data block, and device UID (where -16 = 0xF0 and -9 = 0xF7, as signed 8-bit ints).
hjh
Working instructions to compile Pd for macOS 12 (intel)?
@rbd well I think my instructions above should work, but also you can read INSTALL.txt in the main directory of the source in order to build the binary.
or the manual section: http://msp.ucsd.edu/Pd_documentation/x6.htm
Then you can read the README.txt file in the mac folder, and use the help from the referenced scripts in that directory.
Of course personally I follow the steps I outlined above: when first making the binary don't do make install
or make app
, instead just do make
. Then cd
to the mac directory and make the app using the scripts there.
Passing a list as parameter to csound6~
@zigmhount My Csound is abit rusty but a quick look over the csd. The scale is just an ftable in the score and we can change that with the [event( message, but you would need to rework the Instr Setup
function at the end of the csd to work with values directly from the score's ftable instead of the scale definition at the start. This should allow you to send your scales from pd. The Csound Floss Manual should be able to help, sections 3-D and 9-A being the pertinent sections but you may need to run through the section 2 and the first parts of section 3 just to get the basics down, depending on programming experience. There is also a rather slow Csound forum that may provide better help. Csound is really great for audio generation and fairly simple to learn, it's biggest issue is the insane number of ugens can overwhelm.
A bug just for @jameslo on his expensive holiday
@ddw_music By "straightforward" I don't mean to say that everything's convenient, only that the complications aren't rocket science. I think of it like picking crab meat--potentially annoying, but anyone can do it (and will do it well if they like crab enough). But maybe I'm wrong, gimme examples.
I'll start with ipoke~.c which is really simple because it only consists of loops and branching. ipoke~.c
In section 1 you can see the algorithm processing each sample of the audio and position vector in turn, and I decided to hard-code 64 sample blocks to reduce the number of things that I could screw up. Section 2 is a simple branch based on a test, which you could translate as a [select] or [route] among other ways. To make it run AFAP I think the author avoided function calls in favor of nested if-then-else statements, but to me they're hard to read and understand so I made sections 3 and 4 subpatches, which are like subroutines in that they hide distracting details. (No disrespect to the author implied--the code is beautifully formatted and commented) Finally, if you can find the end of that first if-then-else you will see that there is some post processing for both cases--the current index is copied into the last index in preparation for the next iteration. That's section 5.
Porting loops is just a little complicated by the fact that Pd only has one looping construct with which to make for, while, and do-while loops. Pd is kind of spartan that way.
Moving on to recursion, if you've ever programmed in assembler, you'd know exactly what to do because assembler doesn't have function calls. If you want them you have to make them yourself or write a macro to generate them. The way I learned is to start by pushing the address of the next instruction after the call, then push the function arguments, and then jump to the beginning of the function code. The function code then can pop args off the stack (or just read them in place), and to return it simply jumps to the return address that the caller pushed on the stack and restores the stack to its original state.
Since there's no return mechanism in Pd (@ddw_music pondered that earlier in this forum) we just need to push and pop the arguments at the appropriate points. Here's my port of quicksort: quicksort hoare.pd
First, look at the circled Pd section in the upper right. That's the top call of quicksort(). You can see I'm pushing the low and high indexes of the entire array, and then banging the quicksort graph--that's how you "call" that Pd function with args. Section 1 is the entry into the function--it gets its arguments from the stack and then proceeds with its processing. Phrases 2 and 3 are the "tail recursion" calls, and since their order doesn't matter, I didn't use a [trigger] on the output of [pd partition]. First, the partitioned boundaries are pushed for each recursive call, and then we just let [until] bang the quicksort graph again. When there are no more args on the stack, there are no more recursive calls to process, and so we bang "done" to stop [until]. Rewriting tail recursion as iteration is one of those exercises they give CS undergrads.
If you can guarantee that the recursion is very shallow, then you can simply use message feedback to implement it, but the way I just demonstrated is full-strength; the recursive depth is limited only by the maximum list length.
So in both cases you can see that I'm just creating equivalent graphs in Pd on the right for the procedural textual code on the left. No refactoring, no use of special Pd facilities, no particular creative insight into the algorithms.
summer: an additive synthesizer with per-partial ADSR amplitude envelopes & LFOs
@HollyB I am near useless with pd audio so I can offer no help there but it seems to work and I am having fun with it. Best to ask technical questions in the tech help section of the forum, such questions rarely get answered in the patch/abstraction sections. Your input setup can be troublesome as it always responds to all midi channels. [pdcontrol] makes it possible to have a more elegant setup. With something like this you can call your abstraction with [summer 5] and it will run summer on midi channel 5, or you can turn midi on/off by sending the messages [midi-on{ or [midi-off( and you can change the channel with [mchannel #(. If you load [summer] with no arguments it turns off midi input and uses the [inlet] only.
midi-in-args.pd