I'm mystified. In this code:
SynthDef(\acid,
{
|out, gate = 1, freq, myParam, amp, cutoff, resonance, filtEnvAmt|
var env, audio, filtEnv;
if (myParam == \something, { freq = 200; });
env = Linen.kr(gate, 0, 1, 0, doneAction: 2);
audio = LFSaw.ar(freq, mul: amp);
filtEnv = Line.kr(midicps(cutoff + filtEnvAmt), midicps(cutoff), 0.2);
audio = RLPFD.ar(audio, ffreq: filtEnv + MouseX.kr(0, 5000), res: MouseY.kr(0, 1), dist: 0);
Out.ar(out, audio * env);
}
).add;
b = Pbind(*[
out: 0,
instrument: \acid,
stepsPerOctave: 19,
scale: [0, 3, 5, 8, 11, 14, 17],
octave: 3,
degree: Pseq([0, \, 3, 3, 4, 4, 9, 4, 4]),
myParam: \something,
//prevFreq: Pseq([0, 0, 0, 0, 9, 0, 0, 0, 0]),
dur: Pseq([0.4, 0.4, 0.1, 0.1, 0.1, 0.1, 0.2, 0.1, 0.1]),
cutoff: Pseq([60, \, 50, 60, 80, 60, 90, 80, 50]),
filtEnvAmt: Pseq([20, \, 20, 20, 20, 20, -10, 20, 20]),
resonance: Pseq([0.5, \, 0.5, 0.5, 0.5, 0.5, 0.3, 0.5, 0.5])
]);
b.play;
..the equality test myParam == \something never returns true, despite the fact that the Pbind is clearly sending \something each time. No other value will work either: 0, nil etc.
The equality tests myParam == myParam and \something == \something do work however, so in these cases I get a monotone melody.
I can only guess that a Pbind sends each value in some kind of wrapper, but I've no idea how to then check them from inside the synth. Can anyone help?
First: you can't send symbols to a synth control. You can only send numbers.
Second: your example doesn't say what freq should be if the test is false. In fact, you should write it in more of a dataflow style such as:
freq = if(testcondition, 200, 300);
That's the kind of thing that will work in a synthdef.
Third is a slightly frustrating thing in sc language, which is that the == message is always evaluated at synthdef compile time - the equality is checked once, and then never again. In order to have "live" equality checking, you can use this slightly clunky expression:
BinaryOpUGen("==", thinga, thingb)
So in summary you might write
freq = if(BinaryOpUGen("==", myParam, 1), 200, 300);
Related
I need to generate an array of random 20 bytes between a given range of arrays. Since arrays are comparable in Rust, this works:
let low = [0u8; 20];
let high = [2u8; 20];
assert_eq!(true, low < high);
assert_eq!(false, low > high);
assert_eq!(true, low == [0u8; 20]);
For these bounds:
let low: [u8; 20] = [98, 0, 1, 0, 2, 6, 99, 3, 0, 5, 23, 3, 5, 6, 11, 8, 0, 2, 0, 17];
let high: [u8; 20] = [99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
These would be a valid result:
[98, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
These are not:
[98, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]
I want to do something like:
use rand::prelude::*;
fn main() {
let low = [0u8; 20];
let high = [2u8; 20];
let value = rand::thread_rng().gen_range(low, high);
println!("{:?}", value);
}
but I get following error:
error[E0277]: the trait bound `[u8; 20]: rand::distributions::uniform::SampleUniform` is not satisfied
--> src\main.rs:6:36
|
6 | let value = rand::thread_rng().gen_range(low, high);
| ^^^^^^^^^ the trait `rand::distributions::uniform::SampleUniform` is not implemented for `[u8; 20]`
I tried implementing SampleUniform and UniformSampler without much success. Is there a simple way to implement this?
If you want to treat the byte arrays as big integers, use the
num-bigint crate with the rand feature enabled:
use bigint::{ToBigInt, RandBigInt};
let low = -10000.to_bigint().unwrap();
let high = 10000.to_bigint().unwrap();
let b = rng.gen_bigint_range(&low, &high);
You could also use unsigned integers instead of signed. There are methods to convert to and from big endian byte arrays:
from_bytes_be
to_bytes_be
See also:
How do I generate a random num::BigUint?
Using the excellent guide by Nadieh Bremer I'm making a stretched chord diagram.
However, with certain data inputs the rendering goes awry.
I've made a demo to demonstrate my issue here:
https://codepen.io/benmayocode/pen/MPEwdr
Specifically, in the .js file lines 269 to 281 file I have:
var respondents = 40,
emptyPerc = 0.4,
emptyStroke = Math.round(respondents*emptyPerc);
var Names = ['BEN', 'ROSE', '', '1', '2', '6', ''];
var matrix = [
[0, 0, 0, 10, 10, 0, 0] ,
[0, 0, 0, 0, 10, 10, 0] ,
[0, 0, 0, 0, 0, 0, 24] ,
[10, 0, 0, 0, 0, 0, 0] ,
[10, 10, 0, 0, 0, 0, 0] ,
[0, 10, 0, 0, 0, 0, 0] ,
[0, 0, 0, 24, 0, 0, 0] ,
];
This renders incorrectly - but if I change it to...
var respondents = 40,
emptyPerc = 0.4,
emptyStroke = Math.round(respondents*emptyPerc);
var Names = ['BEN', 'LIB', 'ROSE', '', '1', '2', '6', ''];
var matrix = [
[0, 0, 0, 0, 10, 10, 0, 0] ,
[0, 0, 0, 0, 0, 10, 0, 0] ,
[0, 0, 0, 0, 0, 10, 10, 0] ,
[0, 0, 0, 0, 0, 0, 0, 24] ,
[10, 0, 0, 0, 0, 0, 0, 0] ,
[10, 10, 10, 0, 0, 0, 0, 0] ,
[0, 0, 10, 0, 0, 0, 0, 0] ,
[0, 0, 0, 0, 24, 0, 0, 0] ,
];
Then it works great. I obviously see the difference between the two blocks of code, but why are they producing different results, and is it possible to modify my code to accommodate both examples?
If you examine the dodgy arc, you will see you can flip it into the right place by altering the sign on the transform from (50,0) to (-50,0). If you then look at the code that assigns the transform, it is
.attr("transform", function(d, i) {
d.pullOutSize = pullOutSize * ( d.startAngle + 0.01 > Math.PI ? -1 : 1);
return "translate(" + d.pullOutSize + ',' + 0 + ")";
});
with a note in the original text to say that "the 0.01 is for rounding errors". Given that the startAngle is already 3.13--i.e. very close to Pi--it looks like this is an edge case where the value fell just the wrong side of the cutoff. Changing the allowable rounding error value to 0.02 puts the arc in the correct place, or you could do something like
d.pullOutSize = pullOutSize * (
// is the start angle less than Pi?
d.startAngle + 0.01 < Math.PI ? 1 :
// if yes, is the end angle also less than Pi?
d.endAngle < Math.PI ? 1 : -1 );
to prevent edge cases like that in your dataset.
I'm not sure whether SuperCollider can deliver moons on sticks, but I'd really like to be able to specify values in my Pbind that are interpreted in the same way as midinote or degree: i.e. converted automatically to a frequency.
So, an excerpt of such a Pbind, which produces a TB-303-style slide from one frequency to another:
b = Pbind(*[
out: 0,
instrument: \acid,
stepsPerOctave: 19,
scale: [0, 3, 5, 8, 11, 14, 17],
octave: 3,
degree: Pseq([0, \, 3, 3, 4, 4, 9, 4, 4]),
prevFreq: Pseq([\, \, 0, 3, 3, 4, 4, 9, 4]),
dur: Pseq([0.4, 0.4, 0.1, 0.1, 0.1, 0.1, 0.2, 0.1, 0.1]),
]);
...it would be super-duper if prevFreq were interpreted as containing degree values in the same way as degree.
In the absence of some kind of automatic conversion, I assume I need to do some kind of calculation within the synth itself in order to convert my values from a degree-type value to an actual frequency. I'm aware I can use foo.midicps to convert midinote-type values to a frequency, but is there a similar convenience function to convert degree-type values to a frequency (presumably also using the current scale and octave values)?
If you look at the helpfile for Event, you can see how it computes the frequency from the degree and scale:
note: #{ // note is the note in halftone steps from the root
(~degree + ~mtranspose).degreeToKey(~scale, ~stepsPerOctave);
}
midinote: #{ // midinote is the midinote (continuous intermediate values)
((~note.value + ~gtranspose + ~root) / ~stepsPerOctave + ~octave) * 12.0;
}
freq: #{
(~midinote.value + ~ctranspose).midicps * ~harmonic;
}
detunedFreq: #{ // finally sent as "freq" to the synth as a parameter, if given
~freq.value + ~detune
}
Event is an associative array and those ~variables can also be used as keys to the array (something which will hopefully become clear in a moment. It's also possible to get access to the events in a Pbind, by using a Pfunc. Let's say we want to calculate the current frequency for your Pbind:
b = Pbind(*[
out: 0,
instrument: \default,
stepsPerOctave: 19,
scale: [0, 3, 5, 8, 11, 14, 17],
octave: 3,
degree: Pseq([0, \, 3, 3, 4, 4, 9, 4, 4]),
dur: Pseq([0.4, 0.4, 0.1, 0.1, 0.1, 0.1, 0.2, 0.1, 0.1]),
foo: Pfunc({|evt|
var note, midinote, freq, detuned, result;
note = (evt[\degree] + evt[\mtranspose]).degreeToKey(evt[\scale], evt[\stepsPerOctave]);
midinote = ((note + evt[\gtranspose] + evt[\root]) / evt[\stepsPerOctave] + evt[\octave]) * 12.0;
freq = (midinote + evt[\ctranspose]).midicps * evt[\harmonic];
detuned = freq + evt[\detune];
detuned.postln;
})
]).play
Those calculations for note, midinote, freq and detuned freq are the same calculations we saw in the event helpfile. Therefore, this Pbind will now print out the frequency that you are currently playing.
What you actually want is the frequency you were previously playing, which we could figure out from your array of previous degrees. Or we could just keep track of the previous frequency in a variable. This will be a lot easier to keep track of!
(
var prev;
b = Pbind(*[
out: 0,
instrument: \default,
stepsPerOctave: 19,
scale: [0, 3, 5, 8, 11, 14, 17],
octave: 3,
degree: Pseq([0, \rest, 3, 3, 4, 4, 9, 4, 4]),
dur: Pseq([0.4, 0.4, 0.1, 0.1, 0.1, 0.1, 0.2, 0.1, 0.1]),
prevFreq: Pfunc({|evt|
var note, midinote, freq, detuned, result;
if (evt[\degree] == \rest, { detuned = \rest} , {
note = (evt[\degree] + evt[\mtranspose]).degreeToKey(evt[\scale], evt[\stepsPerOctave]);
midinote = ((note + evt[\gtranspose] + evt[\root]) / evt[\stepsPerOctave] + evt[\octave]) * 12.0;
freq = (midinote + evt[\ctranspose]).midicps * evt[\harmonic];
detuned = freq + evt[\detune];
});
//detuned.postln;
if (prev.isNil(), {
result = \rest;
} ,
{
result = prev;
});
prev = detuned
})
]).play
)
I have built the following simple synth structure which creates a synth and routes its output through an effects unit:
b = Bus.audio(numChannels: 2);
SynthDef(
"mySynth",
{
|freq, amp, gate = 1|
var vol = 0.5;
var audio = Pulse.ar(freq, 0.5);
var env = EnvGen.kr(Env.perc, doneAction:2);
audio = Pan2.ar(audio, MouseX.kr(-1, 1));
Out.ar(b, audio * env);
}
).add;
SynthDef(
"effects",
{
var audio = In.ar(b, 2);
audio = LPF.ar(audio, MouseY.kr(200, 1000));
//TODO: Implement some crazy, revolutionary effects
Out.ar(0, audio);
}
).add;
// **** Dividing line for executing the code ****
e = Synth(\effects);
p = Pbind(*[
instrument: \mySynth,
scale: #[0, 2, 4, 5, 7, 9, 11],
degree: Pseq([3, 3, 9, 9, 2, 9, 9, 3, 5, 7], inf),
dur: Pseq([0.2, 0.2, 0.2, 0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.1], inf),
amp: Pseq([1, 0.6, 0.9, 0.3, 0.4, 0.9, 0.6, 0.85, 0.3, 0.4], inf),
]);
p.play;
This only produces audible output when I execute the code in a particular way:
I can execute each block individually, in order, and I get audible output.
I can execute the first blocks up to the 'dividing line' comment, then the following blocks, and I get audible output.
If I execute all the code together, I don't get audible output.
I'm guessing there has to be some delay between declaring a SynthDef and then instantiate it using Synth(), while the server does set setup stuff. Can anyone shed any light?
I usually get around this with the Server.sync() method. It pauses execution of the enclosing thread (e.g. a Routine) until all asynchronous server commands have been completed. This includes sending SynthDefs and allocating Buffers. You can pass a Condition argument to Server.sync() for more explicit control.
so for example, you can execute this block in one go:
s = Server.local;
s.boot;
s.doWhenBooted({
Routine {
SynthDef.new(\sine, {
arg out=0, hz=220, dur=4.0;
var snd, amp;
snd = SinOsc.ar(hz);
amp = EnvGen.ar(Env.linen(0.1, dur, 0.1), doneAction:2);
Out.ar(out, (amp*snd).dup);
}).send(s);
s.sync; // waits here
x = Synth.new(\sine);
}.play;
});
It is because you can't just "add" SynthDefs to the server and create an instance of said synth in the same execution. If you "play" the synths as they are executed then an instance of them gets added to the server so that when you call the Synth up for execution it will already be loaded. Working code is included below.
(
b = Bus.audio(numChannels: 2);
SynthDef(
"mySynth",
{
|freq, amp, gate = 1|
var vol = 0.5;
var audio = Pulse.ar(freq, 0.5);
var env = EnvGen.kr(Env.perc, doneAction:2);
audio = Pan2.ar(audio, MouseX.kr(-1, 1));
Out.ar(b, audio * env);
}
).play;
SynthDef(
"effects",
{
var audio = In.ar(b, 2);
audio = LPF.ar(audio, MouseY.kr(200, 1000));
//TODO: Implement some crazy, revolutionary effects
Out.ar(0, audio);
}
).play;
// **** Dividing line for executing the code ****
e = Synth(\effects);
p = Pbind(*[
instrument: \mySynth,
scale: #[0, 2, 4, 5, 7, 9, 11],
degree: Pseq([3, 3, 9, 9, 2, 9, 9, 3, 5, 7], inf),
dur: Pseq([0.2, 0.2, 0.2, 0.1, 0.1, 0.2, 0.2, 0.2, 0.1, 0.1], inf),
amp: Pseq([1, 0.6, 0.9, 0.3, 0.4, 0.9, 0.6, 0.85, 0.3, 0.4], inf),
]);
p.play;
)
I'm sure you're right that it's to do with the delay between declaring the synthdef and it being ready.
I'm not really experienced enough with sclang to immediately tell you exactly how you should change your code (I generally use scsynth via OSC, only using sclang to write SynthDefs), but you should be able to do something with the optional completionMsg argument to SynthDef.add.
I was testing around with OpenCV matrices and the display function and had this bug. It took me more than half a day to reveal it:
I originally tried to display OpenCV matrices regardless of the type of matric e.g. CvMat or Mat, ...
with a display method recommended by Mr vasile from another post of mine Multi channel Mat display function
The display method simply fetches all data of the matrix to cout stream
this is my program:
// First: CV_32FC3 works OK
float objpts[12] = {0, 105, 105, 0, 0, 0, 105, 105, 0, 0, 0, 0};
CvMat objptsmat = cvMat( 1, 4, CV_32FC3, objpts);
CvMat* objectPoints = &objptsmat;
CvMatShow(objectPoints);
getchar();
output:
// Second: CV_64FC3 crashes
float objpts[12] = {0, 105, 105, 0, 0, 0, 105, 105, 0, 0, 0, 0};
CvMat objptsmat = cvMat( 1, 4, CV_64FC3, objpts);
CvMat* objectPoints = &objptsmat;
CvMatShow(objectPoints);
getchar();
output:
they should be both the same. Right??!!
In the second example, you should have the array declared as
double objpts[12] = {0, 105, 105, 0, 0, 0, 105, 105, 0, 0, 0, 0};
You can read CV_xxtCn as
xx: number of bits
t: type (F = floating point type, S = signed integer, U = unsigned integer)
n: number of channels