Why does it matter how I execute this code? - supercollider

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.

Related

threejs applyMatrix4 appears to do nothing

The method applyMatrix4 seems like it does nothing...
Why can I not apply this transformation matrix to my vector?
const vec = new THREE.Vector3(1,1,1)
const geometry = new THREE.BoxGeometry(1,1,1)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })
const mesh = new THREE.Mesh(geometry, material)
mesh.rotateX(Math.PI)
const rotatedVec = vec.applyMatrix4(mesh.matrix)
console.log(rotatedVec)
Expectation (taking the cross product):
{x: 1, y: -1, z: -1}
Reality (the vector is unchanged)
{x: 1, y: 1, z: 1}
My mesh's matrix has changed - it is not the identity matrix.
[
[1, 0, 0, 0],
[0, -1, 0, 0],
[0, 0, -1, 0],
[0, 0, 0, 1],
]
Object3D.rotateX() only affects the object's quaternion property. It does not update its local matrix. If you say your matrix has changed, I assume you have checked it at a later point when other engine logic triggers a recalculation.
You can solve this issue by adding mesh.updateMatrix(); after you have called Object3D.rotateX().
Or even better use Vector3.applyQuaternion(). In this way, you don't have to recompute the matrix because you don't need it anyway.
const rotatedVec = vec.applyQuaternion(mesh.quaternion)

d3 Date Axis "Rounding"

I'm attempting to have an X-Axis with dates. Unfortunately my data can be have a small range resulting in a date showing multiple times as an xTick. Is there a way to force it to only show "each date" exactly once as a tick.
For example, I don't want to see 12/29/2020 as a tick more than once.
Depends on your version of d3, but d3.timeDay might be what you need.
var input = [new Date(1999, 11, 31, 0),new Date(2000, 0, 1, 0), new Date(2000, 0, 1, 2), new Date(2000, 0, 1, 3), new Date(2000, 0, 2, 2), new Date(2000, 0, 2, 5)];
console.log(input);
var x = d3.scaleTime().domain(input);
var xTick = x.ticks(d3.timeDay.every(1));
console.log(xTick)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Why can't I do an equality test of a synth parameter?

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);

Can I send values in a Pbind that are interpreted like midinote or degree?

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
)

glMultiDrawElements stops my code

I'm trying to learn OpenGL with "the redbook", and I'm now at the point were I'm testing glMultiDrawElements. I already got my code to work with glDrawElements, and other "simpler" methods, but it stops working here, and now I'm completly stuck. My code is supposed to draw a cube, and the acctuall drawing code is posted under:
GLfloat verticies[] = {-0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5};
glVertexPointer(3, GL_FLOAT, 0, verticies);
GLubyte front[] = {4, 5, 6, 7};
GLubyte left[] = {0, 3, 7, 4};
GLubyte right[] = {5, 1, 2, 6};
GLubyte back[] = {0, 1, 2, 3};
GLubyte bottom[] = {0, 1, 5, 4};
GLubyte topp[] = {2, 3, 7, 6};
GLvoid *faces[6] = {front, left, right, back, bottom, topp};
glMultiDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, faces, 6);
glFlush();
The program is cocoa based, and compile fine, but stops under running due to "EXC_BAD_ACCESS". There is a yellow warning triangle next to glMultiDrawElements(..) saying "incompatible integer to pointer conversion", but i tought i was using pointers in the "faces" array (at least that exactly how it looks in "the red book"). Can somone help me?
The second parameter to glMultiDrawElements() is a pointer to an array of sizes, not a numerical value for a size. This is why the compiler is complaining about an integer to pointer conversion (which, by the way, is another reason why you should enable the compiler flag for turning warnings into errors when doing Cocoa development).
I believe changing the above to read
GLsizei count[] = {4, 4, 4, 4, 4, 4};
glMultiDrawElements(GL_QUADS, count, GL_UNSIGNED_BYTE, faces, 6);
should work, but I haven't tested it here.

Resources