Shell using cd command
@raynovich said:
Does ofelia take over the "terminal" or some other function for Pure Data if created?
TL;DR Probably the best solution is for you to construct the commands with full paths, pointing exactly where you want, and do not rely on the current working directory.
I.e. not cd xxx/yyy/zzz && ls
, but ls xxx/yyy/zzz
.
Why?
"Shell" functions (as I understand it -- maybe it's different in some programming environments, but this is my observation) generally don't persist their state.
That is, if you open a terminal window, there is one shell, and every command operates on the same shell. cd
changes the current working directory of the shell, and the next command remembers the new cwd.
An object like [shell] is like opening a new terminal window for every command. Every invocation starts from scratch. So you should not expect it to work if you ask shell to first cd, then ls. (You said this worked, but I was not able to get that behavior on my machine.)
SuperCollider has a couple of ways to do it that illustrate the issues involved.
"ls".unixCmd; // user home
"cd tmp".unixCmd; // no output, OK
"ls".unixCmd; // still user home
The cd
did not affect the second ls
-- because it's like: terminal window 1, ls
; terminal window 2, cd
; terminal window 3, ls
and why would you expect window 2 to affect the behavior of window 3?
Many shells, when parsing the typed input, can handle a series of commands separated by &&
:
"cd tmp && ls".unixCmd; // lists ~/tmp, OK!
But this is a parsing feature. If a backend issues the command in a different way -- as an array of strings, where the first string is the command and the other strings are arguments, one by one -- this bypasses the parser (because the arguments are already parsed into the array), and the &&
trick no longer works.
"cd tmp && ls".split($ ).postcs.unixCmd;
[ "cd", "tmp", "&&", "ls" ]
(and no `ls` listing)
[shell], as far as I can see, works in this second way. A message like ls tmp
works only if it's a list of two symbols. If you try to make it a single command string -- ls\ tmp
-- then it fails, because there is no system command named l-s-space-t-m-p. (In SC, "ls tmp".unixCmd
runs the command through the shell's parser, which splits a string into command-and-argument. That usage isn't supported in [shell]. Maybe it's supported in [command] but I didn't take a look.)
hjh
how can I track a specific sequence of numbers output in a number box by a random object?
another question now... Once this sequence is detected, I want to play a specific tonal sequence (so in my patch it comes down to a specific series of numbers written one after the other in one specific number box).
I tried to use the trigger object, but the issue there is that trigger outputs it instantly in human-perceived time. Whereas what I need is each number being messaged into the number box following a specific bpm which I get constant triggers of from somewhere else in my patch (it also is not possible to divert from it by using a specific metro object as my bpm subpatch has a constant evolution with an LFO varying with another LFO to have a constant organic BPM change).
Basically I wonder if there is a way to use something such as a trigger object that orders the messages to send, but does it following the trigger it receives and not all of them from one trigger.
playing video in pd and internal midi sound
@KMETE said:
Any example for a simple midi player in Pd?
I'm not completely sure what you mean by "simple MIDI player," but I'll assume you want some Linux software that will play General MIDI sounds.
AFAICS from a quick web search, you would probably have to install a GM soundfont, e.g. sudo apt-get install fluid-soundfont-gm
, and play it using software such as FluidSynth.
On my system, it took a little hunting, but I found /usr/share/sounds/sf2/FluidR3_GM.sf2
-- fluid, check, GM, check.
You'd probably have to connect Pd MIDI out to FluidSynth MIDI in. That should do it.
Is there any transport and tempo object in PD same as in max?
"Same as Max" -- well, no. Does Pd have its own way of handling tempo? Yes.
[metro] and [delay] objects respond to "tempo" messages -- see their help files. (Though unfortunately, some other timing-related objects such as [pipe] and [makenote] do not respond to tempo messages.)
Pd doesn't have a global transport. You could make your own bars/beats counter and [send] those values around in the patch. (I'm not sure if you need a master scheduler -- if so, there's one in https://github.com/jamshark70/hjh-abs .)
This appears to handle the different subdivisions.
hjh
BPM stretchable audio looper
Hello!
I'm working on an audio looper that will stretch based on BPM changes detected by Ableton Link. Not sure if this is remotely the best way to go about things but the project I'm using this in is quite noisy and therefore what might be unacceptable to some might be exciting to us, and perhaps you as well.
Astute readers of this forum may detect that I have lifted solutions from this thread: https://forum.pdpatchrepo.info/topic/6403/timestretch-abstractions
This is a proof of concept for now and I will update as things get more ironed out. Enjoy!
Opening a patch through xdg-open (terminal) will open a new pd instance
Everything should work now.
Some very naive tcl coming through, but it works and hopefully someone who is not ignorant of tcl will make it sane. Seems like there should be a better way to do this than constantly checking for a file, someway to send a message but I am a complete hack when it comes to tcl and I do not really get along with it. Suppose this should be done in its own namespace as well. But it works.
Create a file called pdopen-plugin.tcl and put this in it, save it somewhere in your pd path.
file delete /tmp/pdopenfile
proc pdopen {} {
if { [file exists /tmp/pdopenfile] == 1} {
set f [open /tmp/pdopenfile]
set fp [read $f]
file delete /tmp/pdopenfile
close $f
pdsend "pd open $fp"
}
after 100 pdopen
}
pdopen
And a bash script, save this as pdopen, run chmod +x pdopen
and then copy this to your users path or somewhere like /usr/bin or /local/bin or where ever user installed programs go on your distro if you want it global for all users.
#!/bin/bash
fp=$(readlink -f $1)
if [[ $(pidof pd) ]];
then
f=$(basename $fp);
p=$(dirname $fp);
echo "$f" "$p" >> /tmp/pdopenfile
else
pd "$fp";
fi
Now you do not need a patch open with a [netreceive], just make pdopen the default application for .pd files and if there is a running instance of pd it will open them in that instance, if not it will start up pd.
Beat information in MIDI files
@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 line 0 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.
BPM/Pitch calculator
@lead said:
So what I actually mean is I want to minimise the error in a BPM change of two semitones, and find the start and end values where it's lowest, even if they're both fractions. I think?
Yes -- you'd have an error value for the starting bpm, and another error value for bpm * ratio
, and you would want to minimize the sum.
The tricky thing mathematically is that the error function is piecewise -- every time you jump to the next round in point, it's a different segment. So calculus-based methods for continuous functions couldn't be used directly.
Playing around with it in SuperCollider, though (not Pd, for two reasons: 1/ SC has double-precision floats, 2/ Pd is clumsy at array math):
~error = { |a, b, factor = 0.001|
(a absdif: a.round(factor))
+
(b absdif: b.round(factor))
};
r = -2.midiratio;
f = 69;
// let's test 0.005 bpm on either side .. 1001 total
a = (f - 0.005, f - 0.00499 .. f + 0.005);
b = a * r; // slower bpms
c = ~error.(a, b); // SC auto-expands math ops to arrays!
c.plot;
c.minIndex; // 500
a[c.minIndex] // 68.999999999994 --> 69
So your "good" one is as good as that range is going to get.
Now, if you do the same thing for f = 77, the minIndex is 700 -- not 500 in the middle! -- and a[c.minIndex] = 77.001999999992 or basically 77.002.
Then:
((77.002 * r) absdif: round(77.002 * r, 0.001)) = 1.6905725900074e-05
((77.000 * r) absdif: round(77.000 * r, 0.001)) = 0.00020129683781533
So that shift of 0.002 bpm makes a huge difference.
This test also shows there's no benefit in checking "original" bpm that are not rounded to 0.001. So change it to a = (f - 0.005, f - 0.004 .. f + 0.005);
. EDIT: In that case, the "a" term in the ~error function will be 0 (if factor = 0.001) so you could simplify to:
~error = { |a, factor = 0.001|
a absdif: a.round(factor)
};
// and...
c = ~error.(b);
... which then does come back around to the problem that jameslo linked.
It's a brute-force technique but should work for the purpose.
hjh
BPM/Pitch calculator
@lead said:
So, starting with the smallest number of decimal places and ending with the smallest number of decimal places is preferable, does that make sense?
Formally, it doesn't make sense.
The ratio for 2 semitones down is 2 ** (-2 / 12)
. 2 is a prime number. Raising any (positive) prime number to a fractional power results in an irrational number, with infinitely many decimal places (without ending up in a repeating sequence).
A rational number times an irrational number must be irrational. So your initial bpm value * the ratio is irrational and has infinitely many decimal places. To say "this one has 3 places" glosses over the real situation.
What you're really doing is rounding this irrational number to an arbitrary number of places. The denominator of the rounded number will be 10 ** num_places
-- thus both the numerator and denominator are integers and the result is rational.
The difference (or quotient, depending how you want to measure it) between bpm * ratio
and the rounded version is an error value.
And the math problem, then, is to minimize the error.
You can see it more clearly if you use a language with double precision floats, e.g., SuperCollider:
f = { |bpm, semitones = -2, places = 3|
var r = 2 ** (semitones / 12); // '.midiratio'
var bpm2 = bpm * r;
var rounded = bpm2.round(10 ** places.neg);
// for easier comparison I'll "absolute-value" the error values
var errorDiff = bpm2 absdif: rounded;
var errorRatio = bpm2 / rounded;
if(errorRatio < 1) { errorRatio = 1 / errorRatio };
[bpm2, errorDiff, errorRatio]
};
f.value(69); // [ 61.472011551683, 1.1551683407163e-05, 1.0000001879178 ]
f.value(59); // [ 52.56302437028, 2.4370280016228e-05, 1.0000004636394 ]
f.value(77); // [ 68.599201296806, 0.00020129680612513, 1.0000029343985 ]
... where, indeed, the error for 77 * r is about an order of magnitude worse.
@jameslo -- "It would be cool if you were asking https://math.stackexchange.com/questions/2438510/can-i-find-the-closest-rational-to-any-given-real-if-i-assume-that-the-denomina "
I think this is exactly what the problem reduces to -- what is the closest rational to x
where the denominator = 1000. (However, the numerical methods in the thread will likely evaluate better with double precision floats. Pd prints 6 digits so it may not be clear what you're seeing.)
Actually something else... if x is the original bpm and y is the adjusted, find x and y where the error is minimized. So far the assumption is that x is an integer, but maybe the error could be even lower if they're both fractions.
hjh
Tempo symbols
Help is unclear: You can write e.g. bpm as "tempo x min" or "tempo x minutes" or "tempo x permin" or ... here's the one that is not clearly documented, is it "tempo x perminute" or "tempo x perminutes"?
Reading the help literally it would be "perminutes" but nobody talks like that.
[metro] does not print errors for wrong unit symbols so I can't guess it that way. (Not to mention that the point of good documentation is to eliminate this sort of guesswork.)
Does anyone know?
hjh
Polyrytm , dividing master metro
I am having some issues here with automating the tempo of second metro (denominator )
The structure is pretty simple
There are 2 metro objects , a red and a blue one
The red one (bottom left corner and left channel ) is triggering a sine , the blue metro is triggering another sine ( bottom right right channel).
Both are using a curve envelope ( cyclone )
The master tempo is located at the top , default is 90 bpm
This goes into a tbf , the float is first send to he right inlet of a division , then the bang is triggering a message of 60000 ms
The result is the time of a beat (one minute divided by BPM) .
It all works fine when disabling-enabling mast toggle but that's not what I want.
Now the issue , the purple and orange boxes all house different denomitor values , used to calculate the new tempo for the second metro ( blue right channel )
When manually triggered these go into a tff , the right outlet of tff goes into a division modue ( green box) and the left output
is trigerring a bang to redo the calculation .
As some of you have guessed , when doing this realtime the second metro is losing sync because of the recalculation .
I tried to automate this ( yellow box, enable spigot ) by sending a bang from the master RED metro into a count-selet module , the ouput is triggering new
denominator values that is send to the tff module (using send receive boxes ) , but again Blue metro is not starting on sync .
Anyone help is appreciated to keep blue metro on sync when receiving a new value .