-
zigmhount
posted in technical issues • read moreI've progressed with libpd instead :D
I know that this will probably make things more difficult with complicated patches and externals (I would have to compile libpd with support for these externals if I understand correctly), but for simple patches it seems pretty straightforward. I haven't tested it properly yet, but this small script exposes virtual ALSA-MIDI ports in a patchbay (which I can connect to anything) and just forwards notes and CCs to Pd, and receives Pd's notes and CC back and forwards it out to ALSA:import mido # install python-rtmidi from pip from functools import partial from pylibpd import * my_client_name='My Libpd Client' input_port_name='Input' output_port_name='Output' # Open Input and Output ports (Rtmidi) # Creating multiple virtual ports will create multiple clients with the same name. outport = mido.open_output(output_port_name,virtual=True,client_name=my_client_name) inport = mido.open_input(name=input_port_name,virtual=True,client_name=my_client_name) def pd_receive(*s): print('Printed by pd:', s) def midi_out(*s): match s[0]: case 'note': if s[3] > 0: m=mido.Message('note_on', channel=s[1], note=s[2], velocity=s[3]) else: m=mido.Message('note_off', channel=s[1], note=s[2], velocity=s[3]) case 'cc': m.mido.Message('control_change', channel=s[1], control=s[2], value=s[3]) outport.send(m) # Callbacks to receive messages from Pd: libpd_set_print_callback(pd_receive) libpd_set_midibyte_callback(pd_receive) libpd_set_noteon_callback(partial(midi_out,'note')) libpd_set_controlchange_callback(partial(midi_out,'cc')) libpd_open_patch('midi_processing.pd','.') with inport: for msg in inport: match msg.type: case 'note_on': libpd_noteon(msg.channel,msg.note,msg.velocity) case 'note_off': libpd_noteon(msg.channel,msg.note,0) case 'control_change': libpd_controlchange(msg.channel,msg.controller,msg.value) case 'sysex': libpd_sysrealtime(1,msg.byte) libpd_release()And that's it! It's quick & dirty and it will get more complicated if I need to handle any type of MIDI messages, but notes and CCs should do for now.
Looks like this in the patchbay:

-
zigmhount
posted in technical issues • read moreThanks both,
@oid I have indeed used scripts before, callingaconnectto list, extract the name of the client/port I need to connect to Pd, and connect it to Pd's inputs and outputs. However in the current case I'd like very much something more modular to connect in a patchbay.
@whale-av thanks, I didn't know about the mediasettings external, this will probably useful in the future. Similar to @oid's suggestion though, this is also about connecting Pd with other MIDI clients from within the Pd patch.I'll continue exploring the libpd route, but I'll have to learn a bit more about Python's modules management to figure out how to properly install and use it.
Or maybe open the patch in plugdata inside a plugin host... -
zigmhount
posted in technical issues • read moreHi all,
I've built 3 small Pd patches to fit in my workflow, e.g. to convert one MIDI controller's messages into OSC, one to light up the LEDs of another controller, one to control a pedal, etc.
If I open 2 instances of Pd, each with its own MIDI (or audio, for that matter) inputs and outputs, Alsa-Midi refers to them as follows:
$ aconnect -l client 128: 'Pure Data' [type=user,pid=260121] 0 'Pure Data Midi-In 1' 1 'Pure Data Midi-Out 1' client 129: 'Pure Data' [type=user,pid=260548] 0 'Pure Data Midi-In 1' 1 'Pure Data Midi-Out 1' 2 'Pure Data Midi-Out 2'The client name is the same, and the client ID cannot be predicted - depending on which controllers I have plugged in and in which order, it might be any number incremented from 128. The tools that should remember and restore the patching (
jack_patch, Ray Session and the like) struggle the same as I do to figure out which instance of Pd to connect to which controllers.
I want to keep these patches in separate PD instances so I can mix and match, and not necessarily have all of them open, and always rely on the specific instance's MIDI input number and output number.So, here's my question: any idea if it is possible to rename Pd's alsa-midi ports? I found surprisingly little online about this issue, yet I can't really believe that nobody met this issue before...
I've never seen the command line option
-jacknameto actually have an effect, but in any case Pd does not use Jack MIDI as far as I understand.
I've been thinking about running the patch in a libpd wrapper instead, e.g. from a Python script in which I could specify the client's and port names, but I'm struggling a bit to install pylibpd. -
zigmhount
posted in technical issues • read moreThanks for your replies!
My conclusion is indeed that I don't really need to worry about efficiency in this specific case
@seb-harmonik.ar said:
imo the best way would be to use an
[array]for the button in each[clone].Oh interesting, I'll keep that in mind for the next time where I'll have to worry about Pd's performance. I'd have to see if I can handle it all with only numbers (while [text] leaves the possibility to also store and query symbols)..
why would the order change? why couldn't you just write each button's info to the corresponding line number?
The mapping between buttons and sequences may change, e.g. if I shift the buttons to cover the sequences in columns 2 to 9 rather than 1 to 8.
@oid Ecasound is a good suggestion, I looked into it a couple of years ago when I wanted to make music on a 700Mhz single-core Celeron. For the current project I need a graphical LV2 plugin host where I can easily map controller knobs to plugin parameters, side-chain audio outputs and easily insert new busses with synths or soundfonts, i.e. basically the mixer part of a DAW (I'm on Ardour for now, Qtractor could work also) without its timeline, or Non-Mixer if it supported LV2 plugins with their UI. I might consider something modular eventually (e.g. with Carla).
isolate a core and run the DAW on that core, can keep the random dropouts from happening
Also a good idea, I may give it a try. Although so far I've noticed dropouts when enabling synths in Ardour, Pd's calculations are probably negligible in comparison.
@ddw_music Thanks for the benchmark and the explanations, very interesting. Sticking to numbers in arrays rather than text is definitely something to keep in mind for future projects on smaller machines.
-
zigmhount
posted in technical issues • read moreHi @oid, thanks for the suggestion (I usually do split audio and control in different patches) but I forgot to mention that I am not processing any audio at all in this patch

And, also, that this patch is only used to interface my MIDI controller with OSC, so real-time performance is actually not really a big deal. So maybe the performance difference between my option will not be noticeable at all.For reference, the machine I'm running this on has 2 cores at 2GHz, but I'm also running a DAW in parallel to Pd. My previous project was a complete MIDI sequencer, with 24 ticks per beat and relatively fancy UI (moving canvas for sequences progression bars etc.) which lead to relatively heavy load (and low performance), which is why I looked into the [text] topic that I'm asking about here. But I guess that the performance was impacted much more by the continuous UI updates than by the text search

-
zigmhount
posted in technical issues • read moreHey all,
I am integrating a Pd patch with an existing sequencer/looper (Seq192) with an OSC interface, where my patch should convert my MIDI controller's button presses to OSC commands and send back MIDI signal out to lighten the controller's LEDs.
I can retrieve periodically the status and details of all clips/sequences and aggregate it into a list of parameters for each sequence. The LED colors and the actions that the next button press will trigger depend on these parameters, so I need to store them for reuse, which I like doing with [text] objects. I am then handling buttons' light status in a[clone 90](where each instance of the clone handles one button).This should be running on a fairly low-end laptop, so I'm wondering which of these approaches is the most CPU-efficient - if there is any significant difference at all - and I couldn't come up with a way to properly measure the performance difference:
- one
[text define $1-seq-status]object in each clone, with one single line in each. I compare the new sequence status input with[text get $1-seq-status 0]so that I update only line 0 with[text set $1-seq-status]when I know that the content has changed. - one single
[text define all-seq-status]object with 91 lines. I compare the new sequence status with
[ <button number> ( | [text search all-seq-status 0] | [sel -1] | [text get all-seq-status]and if it has changed, I update a button's line with
[ <new status content> ( | | [ <line number> ( | | [text set all-seq-status]The order in which buttons/sequence statuses are listed in the file might change, so I can't really avoid searching at least once per button to update.
- Should I instead uses simple lists in each clone instance? As far as I could test, getting a value from a list was a bit slower than getting a value from a text, but searching in a text was much slower than both. But I don't know the impact of processing 91 lists or text at the same time...
TL;DR: Is it more efficient to
[text search],[text get]and[text set]91 times in one[text]object, or to[text get]and[text set]1 time in each of 91[text]objects? or in 91[list]objects?Since you've gone through this long post and I gave a lot of context, I am of course very open to suggestions to do this in a completely different way :D
Thanks! - one
-
zigmhount
posted in technical issues • read moreI also noticed here..... http://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html
Great resource, thanks! that's going to be useful in future (hopefully I will finish my project before MIDI 2.0 is widely available
)@ddw_music's video will definitely also be useful, in fact I'm working on a patch I want to run with plugdata in Ardour, so it's spot on, thank you very much!
-
zigmhount
posted in technical issues • read more@whale-av Oh that's great, thanks for the [makefile] trick!
I've tried again to send the message as a list and importing it in different notation tools - both Musescore and lilypond do assume the default 120bpm when I do not send any tempo message (not sure how I got the 190bpm yesterday, I can't reproduce...), and all bars disappear when I inject the tempo message (either as a list or as a stream, which in both cases just add a line0 255;in [seq] ). Might be a limitation of [seq] itself.To make that clear, I've updated the default-tempo midi file in Musescore itself to edit the tempo to 89bpm, exported it as midi (reopened it in Lilypond to confirm the tempo is properly interpreted again), and then sent it via [read file_musescore.mid( to [seq] and again [write file.mid( ... Turns out that the tempo information is lost in the transition through [seq], so this probably just means that tempo changes are not supported by [cyclone/seq] ! too bad.
Looking for alternatives, I've found that [mrpeach/midifile] interestingly uses midi ticks.
But I will follow the sequencing tutorial of ELSE instead, and hopefully [else/midi] also supports midi tempo. -
zigmhount
posted in technical issues • read moreThanks @whale-av, I actually did that on purpose since I understand that [seq] expects a stream of real-time midi bytes from [midiin].
But thanks for noticing the mistakes in the numbers, I'll try again with the correct ones!Edit: ah but wait no, I did that because 51 in hexadecimal equals 81 in decimal (just like FF->255) is it wrong?
-
zigmhount
posted in technical issues • read moreSo, I eventually got to this page and finally to this one, which describes the message
FF 51 03 tt tt ttas a tempo change in the MIDI signal.
Long story short, I built a small patch to convert 120BPM into [255, 81, 3, 7, 161, 32( , which I store in [text define midi_tempo] and then send its content to [cyclone/seq] right after [record( .Unfortunately I still get no tempo when importing the MIDI file to Musescore, and I can see only the first 255 byte in the seq editor (the 2nd line is when I started recording notes after ~6.9 seconds).

I'm open to any ideas!

-
zigmhount
posted in technical issues • read moreHi everyone,
I've started using [cyclone/seq] for MIDI sequencing, with the intention of writing and reading saved .mid files, and also importing the .mid files into a notation editor like Lilypond or Musescore. However I realize when opening this file that I don't ever store any tempo information into [cyclone/seq], so that even though I recorded it at 120bpm, Musescore interprets the notes and rythm at 190bpm (I can make notation examples if this isn't clear
).
As far as I understood from a quick read through this and this, I could either:- send the midi clocks i.e. [248( 24 times per beat into [cyclone/seq] while recording. However this seems to show one single bar without tempo in Musescore. Maybe I need to send also start [250( or continue [251( and stop [252( into [seq]?
- instead of "clock", use "ticks" every 10ms that the sequencer can somehow also use to play the midi file at a different tempo than recorded. However I couldn't figure out if ticks are indeed a different value in realtime midi, what I found was 0xF8 = 248, i.e. same as "clocks"...
Do I understand this right? What would be the proper/preferred way to store beat information in [cyclone/seq] and eventually in the midi files?
Thanks for your help!
Zig -
zigmhount
posted in technical issues • read more@oid Thanks for your answer.
I followed your advice and spent quite some time learning a bit how Csound works - a bit overwhelming indeed.Then I realized that I'd love to be able to play this synth when connecting my MIDI controller to my smartphone, so I tried to run a slightly modified version of the CSD file on Csound for Android, but I didn't manage to get anything but crashes. Then I tried with csound6~ as a Pd external on PdDroidParty and MobMuPlat, but externals of course don't work on these. Then I considered running Linux on old smartphones and tablets, but I couldn't properly access the soundcard without root access. Then I fell back and looked for handpan soundfonts, but I could find only 1 or 2 (for free) in a single scale.
Then I finally came back to Pure Data and realized that my best chance was to convert this Csound patch into Pd vanilla and run it on MobMuPlat.
Which I've done! yay!
I've had quite a few challenges and the sound isn't perfect yet, but it works, and I'm also adjusting a few things to my preferences. I'm also including the r_cycle functionalities to tune the Launchpad and it's a lot of fun! I might be able to spend my Sunday sitting in the grass and playing handpan on my MIDI controller connected to my smartphone
I will push it to Github eventually, right now it's still a little too messy for sharing, but if anyone passing by is interested, just let me know!
Cheers! -
zigmhount
posted in technical issues • read moreHi everyone,
I've been playing a bit with a Csound handpan synth from here and I've used the r_cycle external to make a handpan with my Launchpad
(the patch is not very complicated so I didn't try to make it neat, sorry!).
The csound patch maps specific MIDI notes to the synth according to a scale, and the Pd patch lights up the pads so each colored group of pads sends the corresponding MIDI note to CSound:

I'm super happy with it, but the next step is to make it configurable: the csound patch contains many different scales defined with
giNotes = ftgen(0, 0, -<number of notes>, -2, <list of note numbers> ):; B Kurd ;giNotes = ftgen(0, 0, -10, -2, 47, 54, 55, 57, 59, 61, 62, 64, 66, 69) ; B Golden Arcadia giNotes = ftgen(0, 0, -9, -2, 47, 51, 54, 58, 59, 61, 65, 66, 68)So instead of editing the CSD file and changing the color mapping of the launchpad when I want to change scale, I would like to send a list/array/table of note numbers from Pd to [csound6~] via a message (and adjust the MIDI notes sent by the launchpad at the same time).
I know basically nothing about Csound, so I've read up and found examples usingchnget/chnsetorinvaluewhich seem relatively straightforward to change the value of a single int variable. However I don't really have any idea on how to pass the list/array of scale notes using chnset or invalue, or if there is a better way to do it.Maybe someone around here has an idea? Thanks for reading so far in any case

-
zigmhount
posted in technical issues • read more@whale-av Hmm thanks, this sounds like I might actually be better off with running parallel pd processes right from a shell script and communicating via netsend (this laptop has only 2 cores, so audio processing is all running in the same patch anyway, and controls+GUI in the other), rather than trying hard to get it working with [pd~] and possibly hit some more undocumented limitations later on...
I guess I'll try a bit more, and let's see where I end up
-
zigmhount
posted in technical issues • read moreI think I finally figured it out!
Well, not sure it solves all my problems, but at least here is a limitation of pd~: midi inputs and outputs (obviously)! There were a few of those in one of the libraries called by mybigpatch.pd (r_cycle).So here is my way around it, in case it might help others:
- In the main patch, capture notein and send
[notein $1 $2 $3(to[pd~]:

- in the pd~ subprocess, capture the incoming in an abstraction ./myfolder/notein.pd:

and replace all instances of[notein]with[./myfolder/notein] - similarly for noteout, an abstraction ./myfolder/noteout.pd to use in the pd~ subprocess:

and replace all instances of [noteout] with[./myfolder/noteout] - in the main patch, replace noteout with [r noteout]:

- and the same thing with ctlin, ctlout, bendin, bendout, midiin, midiout, etc.
And the command line magic trick (that it took me a while to figure out) in order to replace all this easily in all pd files:
$ sed -i 's+\(touchin\|polytouchin\|bendin\|notein\|ctlin\|midiin\|midiout\|noteout\|ctlout\)+'./myfolder/'&+' *.pd, which will prepend any instance of notein & co with./myfolder/.Improvement suggestions are of course welcome.
Cheers! - In the main patch, capture notein and send
-
zigmhount
posted in technical issues • read more@mtdr2012 Hey, my bug report seems to still be open: https://git.purrdata.net/jwilkes/purr-data/-/issues/672 but maybe you can help solving it over there

I've moved from Purr-data to vanilla a couple of months after that issue so I can't really help anymore, sorry ! I'm focusing less on the UI now, so whenever I need a control for a knob I just use a centered hslider instead. -
zigmhount
posted in technical issues • read moreHello,
I've been working for a few months on a patch that got more complicated than I had planned, and I finally decided to split it into subprocesses to avoid audio clicks when UI elements refresh. In the past I've done it with 2 separate pd processed and osc calls between both, but I'd like to try with [pd~] instead (which I've read about bit never actually used for real).
So as a first step I'm just trying to load my whole complicated patch inside a [pd~] subprocess (with DSP on in both of course) using a simple[pd~ start mybigpatch.pd( | [pd~ -ninsig 8 -noutsig 2]It works with a simple patch in the same folder, however with the big one, the subprocess starts, loads the libraries, and immediately closes, showing only
pd~: No such file or directoryin the parent process' Pd console window.
I get no more details when adding-d 4,-stderr,-verboseor even-noloadbang(in case it's the patch initiation that failed).
My "big patch" will call many abstractions, initiate arrays, soundfilers and load text files into [text] objects so there are quite a few possibilities for not finding files - however the exact same patch starts perfectly from the same folder. Using the whole path to the patch in [pd~ ( also doesn't help.Are there any known limitations to what [pd~] can or cannot do compared to the main parent pd process?
Thanks!
-
zigmhount
posted in I/O hardware diy • read moreAlso, I'm curious about the buttons you'll choose for this!
I can't mold silicon buttons or 3d-print the enclosure myself, so I may have to go for bulky arcade buttons, not sure yet. -
zigmhount
posted in I/O hardware diy • read more@jaffasplaffa I recently built my first device, a USB midi footswitch with an arduino. A bit of googling led me to the awesome MIDI Control Surface library.
The main thing to be careful about IMO is to get the right board to communicate directly over USB (Micro, Leonardo, Teensy, see the documentation), otherwise (Uno, Nano) you will need a serial-MIDI converter software like hairless (with GUI) or ttymidi (command line).
For the LED lighting I took inspiration from my other commercial controllers, and set the arduino's code to light up the LEDs by sending a notein and then it off with a noteoff (if you have multiple colors or blinking mode, you can use different velocities, e.g. 36 1 1 for solid green on button 36 (channel 1), 36 2 1 for blinking green, 36 3 1 for red, etc.
You can also hardcode the LEDs status with the buttons status, but you may loose flexibility (especially when using Pd, but it may be more complicated to use a DAW if you have to set up when to light up the LEDs, not sure).Now I am looking into building another controller with faders and knobs, and there I'll indeed also need multiplexers, as I believe that the bigger Arduino I could find had ~40pins. You will probably need digital pins for the buttons and LEDs, while potentiometers need analog pins (as far as I could understand so far, but I'm also new to this!).
In any case, regardless of how you initially program the arduino (e.g. only notein/noteout to control the LEDs), you can just decide otherwise later on and reprogram it (just like you would update a commercial controller's firmware) to change the note numbers of each button, add special modes to give other functionalities to the same buttons, this kind of things.
Let me know how it goes
I'm hoping to get started on mine in 2 weeks or so. -
zigmhount
posted in technical issues • read moreThank you @oid , I should have thought about that right away!
Turns out thataseqdumpdoesn't show any difference (NoteOn with velocity 0 is interestingly displayed as NoteOff, but it works anyway on the 64bits machine to turn off the LED).I found one cause by chance however: If I connect Pd with the MIDI device via ALSA-MIDI, it works fine, but if I connect them via JACK-MIDI, I can't turn off the LEDs!
So when I connect PD with the controller with
aconnect 130:1 24:0it does work fine on both laptops. Not sure whether that might be caused by a2jmidid in the end, but I guess it is solved (and indeed not related to Pd!).