Wait for OSCdef message in Supercollider, play an event but wait X time before next event - supercollider

If i'm using OSCdef to listen for changes from a function, such as:
OSCdef('listen', {
arg msg;
~trigger = msg[5]; // This value is 0 when off, 1 when on
~amp = msg[3].linexp(0.0, 1.0, 0.7, 0.8 );
~dur = msg[4].linexp(0.1, 1.0, 1.0, 0.01);
~pitch = msg[4].linlin(0.0, 1.0, 80, 800);
}, '/ctrl');
When ~trigger fires, the variable becomes 1. I want to play a synth or open an env to change the sound.
However, when ~trigger fires, it fires for 10 seconds randomly, so you'll have 1,1,0,1,0,0,0,1,0,01,01,01,01,1,01, etc for 10 seconds.
I want to know if it's possible to catch the first 1, play an event and ignore the remaining triggers for the next 10 seconds

Worth looking at "suppressing triggers":
Passing or suppressing triggers: You might need to generate triggers
continuously, but permit the triggers to take effect only when a
condition is met. Multiplication handles this nicely: condition *
trigger. Since the condition evaluates as 0 when false, the trigger
will be replaced by 0 and nothing happens, as desired.\ \ For a simple
case, let’s refine the mic amplitude example by suppressing triggers
that occur within 1/4 second after the previous. var mic = In.ar(8,
1), amplitude = Amplitude.kr(mic), trig = amplitude > 0.2,
timer = Timer.kr(trig), // how long since the last trigger?
filteredTrig = (timer > 0.25) * trig;
SendTrig.kr(filteredTrig, 0, amplitude);
Source: https://supercollider.github.io/tutorials/If-statements-in-a-SynthDef.html

Related

Is there a way to have a delay in between code in p5.js

So I want to have a delay in my Draw function so that when I want to do
Xoffset = Xoffset + 1.5
I do not go from 0 to 30 in a secnd, but I want there to be some delay in the code so that I can easily manage it. I usually use scratch and if you are unfimiliar to that the command for a code delay is
Wait(Insert amount of seconds you want to delay here)
So when you start a part of the code, and the Wait is set to 2, the input will go off, wait 2 seconds, and then move on the the line of code below. I am trying to replicate that but in p5.js.
To detail my comment above, you could do something like this:
var xOffset = 0;
// time delay vars
// current time "snapshot" (imagine pressing the lap time button)
var time;
// the interval to wait between time "snapshots": 2s (2000 milliseconds) in this case
var wait = 2000;
function setup() {
createCanvas(300, 300);
//store the current time
time = millis();
}
function draw() {
background(220);
//check if the difference between now and the previously stored time
// is greater than the wait interval
if(millis() - time >= wait){
console.log(wait, "ms passed");
//if it is, do something
xOffset = xOffset + 1.5;
//also update the stored time
time = millis();
}
circle(xOffset, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
I'm not sure what the main purpose of the delay is:
is it to slow things down for debugging purposes
is to go into a series a states (e.g. ball moves up for 2s, then right
2s, etc.),
is to animate/smoothly interpolate between two positions within a given
time ?
Maybe something else completely ?
If you simply want to slow things down, perhaps it might be simpler to adjust the frameRate():
var xOffset = 0;
function setup() {
createCanvas(300, 300);
// update 1 frame every two seconds => 0.5 fps
frameRate(0.5);
}
function draw() {
background(220);
xOffset = xOffset + 1.5;
circle(xOffset, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
Processing still has a delay() function, but p5.js doesn't.
Personally I'm not a fan of blocking behaviour like this and prefer the millis() options even though it's more verbose. That being said, if the program/demo you write is super simple delay() might just be enough.
Even if delay() is missing you could use js setTimeout() with a Promise, but that's getting into more advanced JS as Paul already mentioned:
var xOffset = 0;
function setup() {
createCanvas(300, 300);
// prevent p5's default draw() updates
noLoop();
}
function draw() {
background(220);
xOffset = xOffset + 1.5;
circle(xOffset, 150, 60);
// wait 2s then call draw() manually
delay(2000).then(draw);
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
Now, if you want to create a smooth animation from a start x offset to an end offset in a set amount of seconds you'd need a different approach.
You can find a p5.js example at the of this answer:
var startTime;
var duration = 2000;
var startValue = 0;
var endValue = 300;
var currentValue = startValue;
function setup(){
createCanvas(300, 300);
textAlign(RIGHT);
startTime = millis();
}
function draw(){
background(255);
moveCircle();
drawCircle();
}
function drawCircle() {
circle(currentValue, 150, 60);
}
function moveCircle(){
var progress = (float)(millis()-startTime)/duration;//millis()-startTime = difference in time from start until now
if(progress < 1.0) currentValue = startValue + (endValue * progress);//the current value is the final value scaled/multiplied by the ratio between the current duration of the update and the total duration
}
function mousePressed(){//reset value and time
currentValue = startValue;
startTime = millis();
}
function keyPressed(){//update duration
if(key == '-') if(duration > 0) duration -= 100;
if(key == '=' || key == '+') duration += 100;
console.log("duration: " + duration);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
And if you're comfortable using external libraries you could simply use a tweening library such as gsap:
var x = 0;
function setup(){
createCanvas(300, 300);
// animate "this" global object's x property to 300 in 2 seconds
gsap.to(this, {x: 300, duration: 2});
}
function draw(){
background(255);
circle(x, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js"></script>
Notice the animation has a bit of easing (default ease out) which could be nice.
In JavaScript, unlike Scratch, there is not a good way to delay synchronous* code. The reason for this is that all the functionality of a webpage is run using a single thread. Which means that while there can be multiple sequences of instructions performing different pieces of functionality, only one of those sequences can execute at a time. Therefore if you did something to delay the execution of JavaScript within the draw() function, it would block all other functionality, making the browser tab unresponsive (and potentially causing the browser to halt your JavaScript altogether).
Instead of pausing a series of JavaScript statements like one would do in Scratch, it is necessary to either use the amount of time that has elapsed as part of a condition that determines whether some code should run (which is what the example George shared in the comments does), or to use the built in setTimeout() function to schedule some code to run some number of milliseconds in the future (but you would not want to call setTimeout() from draw() because it would repeatedly schedule the code every frame).
* note: there are also ways to create delays using asynchronous javascript code, but this is a more advanced topic

Starting a Xamarin.Forms animation (in loop) in the middle

I am playing with the Animation class with a loop in the Commit call, and I'd like to spice it up:
Can I start a (looped) animation in the middle?
Let's say I have the following code that loops an animation in 5 seconds:
// Time in seconds
maxTime = 5;
animation = new Animation(Animation_Handler,
0.0, maxTime * 1000);
animation.Commit(owner: this, name: "test_animation",
length: maxTime * 1000,
repeat: () => true, easing: Easing.Linear);
This will have the handler Animation_Handler start with the argument t = 0 and proceed being called until t = maxTime * 1000, then called again with zero.
Is it possible to start animating with a time t different from zero, avoiding doing it by hand with a time-shift in my animation code?

p5.js Beginner - RNG not working

So i just wanted to make a generator that generates a random value every 10 seconds. And instead it generates a random value every frame after 10 seconds of waiting. Please correct me.
var imgs = [];
var a = 0
function randomizea() {
a = int(random(5));
}
function setup() {
createCanvas(1400, 850);
// for (var i=0; i<5; i++) {
// imgs[i] = loadImage("data/img"+i+".png");
// }
}
function draw() {
background(150, 100, 150);
setInterval(randomizea, 1000);
// image(imgs[a], 0, 0);
text(a, 0, 50);
}
You should generally not use setInterval() with P5.js. Instead, rely on the timing mechanisms that P5.js already gives you.
Here's a simple example that would print something to the console every 10 seconds:
function draw(){
if(frameCount % 600 == 0){
console.log("here");
}
}
Since 60 frames fire per second, then 600 frames is 10 seconds. We use the % modulus operator to check that the frameCount variable is a multiple of 600, which means that we're at a multiple of 10 seconds.
You could also use the millis() function and check whether a certain time has elapsed.
Related posts:
How to make a delay in processing project?
How can I draw only every x frames?
Removing element from ArrayList every 500 frames
Timing based events in Processing
How to add +1 to variable every 10 seconds in Processing?
How to create something happen when time = x
making a “poke back” program in processing
Processing: How do i create an object every “x” time
Timer using frameRate and frame counter reliable?
Adding delay in Processing
Please also consult the P5.js reference for more information.

Resolving a logic issue with Arduino user input

I'm working on an Arduino program that reads data from an anemometer and if the wind is above a certain threshold, it activates a relay. The threshold can be set in two ways:
1) The user can use two buttons to increase or decrease the threshold
2) If a certain button is held for 2 seconds, the threshold will sync with the current wind speed.
My problem is this: the increase and decrease buttons change the threshold value by +/- 0.5 km/h. But the wind speed is read with 0.1 km/h precision. So what can sometimes happen is if the current wind speed is, say, 12.2 km/h, and the sync button is held, the threshold now becomes 12.2 km/h. No problem yet...
But then if the user presses one of the increase/decrease buttons, the threshold still changes by +/- 0.5 km/h, meaning the values will increase like 12.2, 12.7, 13.2, 13.7, etc.
What I would like to have happen is for the increase/decrease buttons to put the threshold value to the nearest 0.5 multiple. So if the sync button was used, and the threshold was set to 12.2, pressing the increase button would change to 12.5, and then continue in steps of 0.5 from there.
I can think of a few ways to fix this issue, but none of them are very elegant. I want to use the simplest solution possible.
Note: I'm not including any of my code because this is more of a logic/pseudocode question. Also, this is my first forum post, so let me know if I need to change anything in my post!
EDIT: Pseudo, by request.
if increase button pressed
threshold+=0.5
if decrease button pressed
threshold-=0.5
if sync button held
threshold = current wind speed
Handle_key_press_down(key, &threshold) {
min_step = 0.5
Hysteresis = min_step*0.6 // Avoid threshold that is exactly same as the current speed
New_threshold = round_to_nearest(threshold, min_step)
If (key == up) {
New_thresh = Threshold + min_step
Else if (key == down) {
New_thresh = Threshold - min_step
Else if (key == sync) {
Wait_for_release
If release_time >= 2.0s
New_thresh = round_to_nearest(Get_current() + Hysteresis, min_step)
Else
ignore
Endif
// Insure, no matter what, threshold is within design limits.
If (New_thresh > threshold_max) New_thresh = threshold_max
If (New_thresh < threshold_min) New_thresh = threshold_min
return New_thresh
}
Sophisticated C++ solution for Arduino (grin)
#include <math.h>
// button == 1 increase, button == 0 decrease
void adjust(float& level, char button) {
float floorVal2=floor(level*2); // level*2 is equiv to level/0.5
if(fabs(floorVal2-2*level)<1e-5 ) {
// they aren't close enough to consider them equal
level=
button
? (floorVal2+1)/2 // this is equiv to ceil(level/0.5)*0.5
: floorVal2/2 // this is floor(level/0.5)*0.5
;
}
else {
level += (button ? 0.5 -0.5)
}
}
void read(float& level) {
level=MySensor::getCurrentValue();
}

Mapping in SuperCollider

I am trying to map amplitude to a synth using a bus in order to smooth out the sine wave (remove high frequencies) based off of semi-random inputs from an outside source, but when I run this code, there is no sound.
s.boot;
(
SynthDef( \cello, {|rate = 440, amp = 0.2|
var signal;
signal = SinOsc.ar(rate, 0, amp);
Out.ar([0,1], signal)}
).add;)
h = Synth( \cello, [ \rate, 440, \amp, 0 ] );
c = Bus.control(s, 2);
c.scope;
Task({
var counter, pyAmp, newAmp, oldAmp = 0;
counter = 0;
{counter < 1}.while ({
pyAmp = 3.0.rand;
(pyAmp).postln;
d = { XLine.ar(oldAmp, pyAmp, 0.1) }.play(outbus: c);
("and").postln;
(oldAmp).postln;
oldAmp = pyAmp;
h.map(\amp, d);
0.1.wait;
})
}).play;
)
You have at least a couple of problems.
Your first XLine synth tries to do an XLine starting from 0. Absolute zero is a problem in exponential-land, it's impossible. Start from a tiny but positive value instead.
You are creating little XLine synths to try and set the amp, but you're never releasing these synths. Lots of them are building up. Who knows what value that amp is adding up to in the end? You should use doneActions to make the synths free themselves.
Thirdly (but not harmful) there's no point running those XLine synths at audio rate, you may as well use XLine.kr not XLine.ar

Resources