# Help with animation doppler sound-wave propagation

Hi!
I am trying to create an abstract animation visualizing how sound waves propagate emitting from a moving object. Basically circles growing in radius while the x position of the object changes.

Like in this animation:

In my code I am missing the characteristic of a sphere constantly emitted from the object. Something needs to be done with opacity and re-trigger. To match the characteristics of the animation in the youtube video. Maybe some one has an idea that could help me? Thank you!

Here is what I got:

``````let xpos = 0;
let ypos = 200;
let radius = 0;
let interval = 0.5;
let waves = [];
function setup() {
createCanvas(800, 400);
}

function draw() {
background(0, 255);
xpos += 6;
// object emitting sound
fill(255);
ellipse(xpos + 6, ypos, 10);

for (let i = 0; i < 1; i++) {
waves.push(new Wave(xpos, ypos, radius));
}

for (let wave of waves) {
wave.update();
wave.show();
}

for (let i = waves.length - 1; i >= 0; i--) {
if (waves[i].finished()) {
waves.splice(i, 1);
}
}
}

class Wave {
constructor(x, y, radius) {
this.pos = createVector(x, y);
this.radius = radius;
this.lifetime = 255;
}

finished() {
return this.lifetime < 0;
}

update() {
this.radius += 40;
this.lifetime -= 9;
}

show() {
stroke(255, this.lifetime);
strokeWeight(2);
noFill(0);
stroke(255, this.lifetime);
strokeWeight(1);
ellipse(this.pos.x, this.pos.y, this.radius);
}
}

``````

maybe itâ€™s a kind of optical illusion

when a circle increases its radius, it takes the position of the last circle and so on. So it looks like nothing moves but the circle do move.

you can see this with random speed of circle growing:

``````let xpos = 9;
let ypos = 200;
let radius = 20;
let interval = 0.5;
let waves = [];

function setup() {
createCanvas(800, 400);
frameRate(1);
}

function draw() {
background(0, 255);

xpos += 15;
// object emitting sound
fill(255);
ellipse(xpos + 6, ypos, 10);

for (let i = 0; i < 2; i++) {
waves.push(new Wave(xpos, ypos, radius));
}

for (let wave of waves) {
wave.update();
wave.show();
}

for (let i = waves.length - 1; i >= 0; i--) {
if (waves[i].finished()) {
waves.splice(i, 1);
}
}
}

class Wave {
constructor(x, y, radius) {
this.pos = createVector(x, y);
this.radius = radius;
this.lifetime = 255;
this.speed = random(17, 88);
}

finished() {
return this.lifetime < 0;
}

update() {
this.radius += this.speed;
this.lifetime -= 9;
}

show() {
stroke(255, this.lifetime);
strokeWeight(2);
noFill(0);
// stroke(255, this.lifetime);
stroke(255);
strokeWeight(1);
ellipse(this.pos.x, this.pos.y, this.radius);
}
}

``````
2 Likes

@Chrisir thatÂ´s interestingâ€¦ Thank you! Experimenting further here

1 Like

@Chrisir I think I made it look a bit better through some additional opacity animation
It still looks unexpected but is should be a quiet adequate representation as it looks like in this more scientific visualization I found here:

``````let xpos = 0;
let ypos = 200;
let radius = 80;
let interval = 5;
let waves = [];
let opacity = 0;

function setup() {
createCanvas(windowWidth, windowHeight);
frameRate(20);
}

function draw() {
background(0);
if (frameCount % (interval * 2) == 0) {
opacity = 180;
} else {
opacity = 50;
}

// object emitting sound moving
xpos = 800 * sin(((frameCount % 60) * TAU) / 60) + width / 2;
ypos = 200;

fill(255);
noStroke(0);
ellipse(xpos, ypos, 30);

//generate soundvaves
for (let i = 0; i < 1; i++) {
waves.push(new Wave(xpos, ypos, radius, opacity));
}

for (let wave of waves) {
wave.update();
wave.show();
}

//loudness out finish
for (let i = waves.length - 1; i >= 0; i--) {
if (waves[i].finished()) {
waves.splice(i, 1);
}
}
}
//soundwaves
class Wave {
constructor(xpos, ypos, radius, opacity) {
this.pos = createVector(xpos, ypos);
this.radius = radius;
this.lifetime = 255;
this.speed = 200;
this.opacity = opacity;
}

finished() {
return this.lifetime < 0;
}

update() {
this.radius += this.speed;
this.lifetime -= 30;
}

show() {
noFill(0);
stroke(this.opacity, this.lifetime);
strokeWeight(4);
ellipse(this.pos.x, this.pos.y, this.radius);
}
}

``````
1 Like

mhhh after watching this video I just posted from youtubeâ€¦ maybe I could jet a smoother result if I would scale the circles instead of increasing the radiusâ€¦

or maybe it looks better because it all happens slowerâ€¦

1 Like

IÂ´ll try some more tomorrow again sigh

1 Like

Finally I have it. I guess it was a bad idea to start from an old particle emiter patchâ€¦ that handled the array differentlyâ€¦ But now I started from scratch and have it working!

``````let timer = 0;
let soundwaves = [];
let period = 50;
let y = 0;
let x = 0;

function setup() {
createCanvas(windowWidth, windowHeight);
}

function draw() {
background(0);
y = windowHeight / 2;
x = 900 * sin(((frameCount % 1800) * TAU) / 1800) + width / 2;
circle(x, y, 20);

if (millis() >= 500 + timer) {
let s = new Soundwave(x, y, 0, 0);
soundwaves.push(s);
timer = millis();
}

noFill(0);
stroke(255);
strokeWeight(1);
for (let i = 0; i < soundwaves.length; i++) {
soundwaves[i].show();
soundwaves[i].update();
}
}

class Soundwave {
constructor(x, y, r, e) {
this.x = x;
this.y = y;
this.r = r;
this.e = e;
}

update() {
this.e += 8;
this.r = this.e;
}

show() {
stroke(255);
strokeWeight(2);
noFill();
circle(this.x, this.y, this.r);
}
}

``````
2 Likes

meanwhile I experimented with WEBGL to animate everything in 3D
Now I run into two problems here. One is not WEBGL specific.

The none WEBGL specific issue: In line 52:
I wish to splice out the oldest (highest radius) soundwave from the array every 2 seconds. But it does not seem to work correctly and causes a hickup in the animation.

The problem that occured with WEBGL In line 37:
Why doesnÂ´t this sphere move as the x position of the class Soundwaves do? They share the same x and y values

``````let timer = 0;
let timersplice = 0;

let soundwaves = [];
let period = 50;
let y = 0;
let x = 0;
let angle1 = 0;
let objperiod = 0.012;

function setup() {
createCanvas(1000, 1000, WEBGL);
}

function draw() {
background(0);

//camera and lightning
camera(0, 1000, 1000, 0, 0, 0, 0, 1, 0);
let dx = 1 - width / 2;
let dy = -1 - height / 2;
let v = createVector(-dx, -dy, 0);
let v2 = createVector(dx, dy, 0);
v.normalize();
v2.normalize();
ambientMaterial(255);
directionalLight(255, 0, 0, v2);
directionalLight(0, 0, 255, v);
ambientLight(0, 0, 50);

//move object and sound waves x and y;
let ampx = (0.3 * width) / 2;
x = map(cos(angle1), -1, 1, ampx, -ampx);
y = 0;
angle1 += objperiod;

//Problem: why doesnÂ´t this sphere move as the x position of the class Soundwaves do? They share the same x and y values
translate(x, y, 0);
sphere(40);

//emit soundwave every 500ms
if (millis() >= 500 + timer) {
let s = new Soundwave(x, y, 0, 0);
soundwaves.push(s);
timer = millis();
}

for (let i = 0; i < soundwaves.length; i++) {
soundwaves[i].show();
soundwaves[i].update();
}
//Problem: I wish to splice out the oldest (highest radius) soundwave from the array every 2 seconds. But it does not seem to work correctly and causes a hickup in the animation.
for (let i = soundwaves.length - 1; i >= 0; i--) {
if (millis() >= 2000 + timersplice) {
soundwaves.splice(i, 1);
timersplice = millis();
}
}
}

class Soundwave {
constructor(x, y, radius, expand) {
this.x = x;
this.y = y;
this.radius = radius;
this.expand = expand;
}

update() {
this.expand += 8;
this.radius = this.expand;
}

show() {
noStroke(0);
translate(this.x, this.y, 0);
torus(this.radius, 10, 80, 12);
}
}

``````
1 Like

Now I feel I have a good version also splicing out after a number of max circles has been reached. I post the 2D version here as itÂ´s final for me:

``````let soundwaves = [];
let interval;
let maxSoundwaves = 10;

let y = 0;
let x = 0;
let angle = 0;
let period = 0.006;

function setup() {
createCanvas(windowWidth, windowHeight);
//add soundwave on interval
interval = setInterval(addSoundwave, 600);
}

function addSoundwave() {
//add soundwave on interval
let s = new Soundwave(x, y, 0, 0);
soundwaves.push(s);
//remove soundwave when max limit
if (soundwaves.length >= maxSoundwaves) {
soundwaves.splice(s, 1);
}
}

function draw() {
background(0);

//move object and sound waves x;
let ampx = 1 * width;
x = map(sin(angle), -1, 1, 0, ampx);
y = 500;
angle += period;

//object
fill(255);
circle(x, y, 20);

for (let soundwave of soundwaves) {
soundwave.show();
soundwave.update();
}
}

class Soundwave {
constructor(x, y, radius, expand) {
this.x = x;
this.y = y;
this.radius = radius;
this.expand = expand;
this.speedofsound = 8;
}

update() {
this.expand += this.speedofsound;
this.radius = this.expand;
}

show() {
//CIRCLE
noFill(0);
stroke(255);
strokeWeight(10);
circle(this.x, this.y, this.radius);
}
}

``````

I still have problems aligning torus the same way when using WEBGL but IÂ´ll make a seperate thread on this.

1 Like

This discussion reminds me of this very old sketch:
â€śWave Triosâ€ť

1 Like