"crossfader" style slider for selecting and blending waveforms/oscillators
the image from fishcrystal contains an important, basic part of the answer in that plot: the math required for a multi-point-crossfader is identical to the math in a "equal-power" stereo panner.
using modulation -> list -> modulo -> cos function, as seen above, is a nice short data rate implementation.
if you want to use signals, where you dont have lists, you can optimize that principle further by using buffers and then only use +- offsets when reading out the function for the different inputs.
How to make a waveform from a mathematical formula
I currently have a formula written out in pure data that constantly calculates the distance between a point and the two edges of an oval. The point is constatenly rotating on this oval. I now need to understand how can I take this math and take the distance of three lines and make it into a wave form that is in constant change based on these values. This motion may be familiar to some of you in the attached image below, however my question is merely once the math is done how can it be translated into a waveform that produces audio?
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!
maths regarding conversion from metro speed to pitch
it is no problem to read from a wavetable in cycles smaller than 1 sample, as long as the wavetable object is able to interpolate.
but running a metro at 0.01 ms might not work for some other reasons,
when trying to "find the right math" the most important thing is that you are aware about what you want to find.
for example the OP is talking about "conversion" from "speed" to "pitch" and later he calls it just "this".
in this situation it can help to write down what the different objects and their functionality actually stands for and break down the problem into smaller parts.
for a wavetable oscillator the following is true: if it is played with a rate of 1.0, its pitch will be a product of its length and the system samplerate,
so write down these values and units and see how they fit together with the rest of the patch.
after you figured this out, the next step could be to find the formula to make it cycle at 261Hz when a middle C is coming in under the condition of a variable system samplerate. this now will only be a rule of three job.
unlike others i dont think you need to learn more about generic maths. the trick is rather to fully understand your own patch.
maths regarding conversion from metro speed to pitch
The relationship between frequency and time is generally 1/x -- time is proportional to 1 / frequency, and vice versa.
The graph of 1/x shows a decreasing curve which flattens out as x goes up. This looks vaguely exponential but it isn't. An exponential function is base^x, but this function is x^(-1).
If you have a cycle of 12 points and you want a frequency f
, then the total time for each cycle is 1000 ms/sec / f cyc/sec, seconds cancel out and you get 1000 ms/cyc. Then you need 12 of these, so divide that by 12. That's the theory anyway.
But timing in the Pd control layer is quantized to the control block size so this is likely to jitter. You might like that sound, but if not, then it would be necessary to shift the whole calculation to the signal domain. I think I can do that later but I'm not free right now (early meeting).
hjh
have 16 "step" array, supposedly counter counts 0...16 - but first and last steps don't get played?
@whale-av said:
@oid Yes, the help file says to start at index one. My maths memory is 60 years old, but I imagine that the polynomial needs a value from the previous index for every calculation (and the following two indexes).
That's correct.
The internet has a lot of garbage in it, but it can actually help with maths memory: https://www.paulinternet.nl/?page=bicubic is an excellent summary.
hjh
Broadcast osc messages to multiple ip adresses with puredata
Hi, thanks a lot for your help. It was very useful for me to understand the whole thing.
First of all, finding the "Broadcast address" is needed in order to reach all ips under the same router.
Finding the broadcast address can be done doing some maths acording to your own ip and the given subnet mask. These maths remain obscure for me but are explained here: [https://www.wikihow.com/Calculate-Network-and-Broadcast-Address
](link url)
Finally I used a calculator, this one: [https://jodies.de/ipcalc](link url)
Then, instead of the needed ip in the **connect **message, I put the given broadcast address followed by the port number and here you are! Worked perfectly!
Thanks a lot for your help @alexandros and @whale-av
note: I'm using oscx library, in my case
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
BPM/Pitch calculator
@lead Sorry, still not quite understanding what you're after. Is the 77 BPM example bad because it has 4 decimal places instead of 3 like your good examples? Or are you asking "which BPMs when pitched down 2 semitones results in a BPM that has as few decimal places as possible?" 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