# Smooth Speed Slider?

**URL:** <https://forum.electromage.com/t/smooth-speed-slider/1249>\
**Category:** Patterns and Code\
**Created:** [May 18, 2021, 8:20pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249 "2021-05-18T20:20:05Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nick\_W](https://forum.electromage.com/letter_avatar_proxy/v4/letter/n/958977/32.png) [@Nick\_W](https://forum.electromage.com/u/Nick_W)\
**Post date:** [May 18, 2021, 8:20pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/1 "2021-05-18T20:20:05Z")

</div>

This is my speed slider:

```auto
export function sliderSpeed(_v) {
  fps = .01 + (3.99 * _v)
  // When slider is full left, _v == 0, speed is .01. 
  // When slider is full right, _v == 1, speed is 4.
}

```

When I use it, my pattern jumps all over the place, and ends up on a random colour as the starting point for the new speed.

I’m assuming this is because `fps` ends up at some new random number when the slider stops moving.

Is there any way to implement a speed control that doesn’t do this? so that I could speed up/slow down the pattern without it jumping all over?

Or would this be a new feature request - ie when the time base in `time()` is changed, it continues with the same number as previously, just increments it faster/slower?

Thanks.

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 18, 2021, 11:16pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/2 "2021-05-18T23:16:01Z")

</div>

So unsure that’s the slider’s fault…

I mean yes the time base is changing… So whatever value assigned by time(x) is changed because you’ve changed the X…

So how to smooth that out…

Example:

Slider populates “speed”

```
y = x // before the speed change... Record X
x = time(speed) // X varies between 0 and 1... 

// Put a new value as a throttle...
// Throttle is 2%, let's say...
If ( abs(y-x) > ( .02 * y) ) {
     If ( (y-x) > 0) {
         y = y * .98;
      } else {
         y = y * 1.02;
     }
  } Else {
    Y = X
  }

```

Use Y as your value. It’ll track X, unless the change is sudden… then it’ll attempt to find a new sync. Ideally, you could make the throttle based on the speed variable… Then it would likely behave even better.

All code is off the top of my head. Errors may occur, my mind is buggy. When I find some time to sit with a PB, I’ll post real code. (For instance, to clamp Y to not go beyond 0…1). It also might depends on if it’s a sawtooth, a wave or what…  
Good problem to ponder.

I’ve actually got a slightly better way now. Basically involving the delta of Y and X, and adjusting that slowly. Might actually use X Y and Z to do it right… I’ll put a demo up tomorrow.

Alternatively, you could throttle/adjust speed. I might try both and see which feel more responsive.

---

<div class="post-metadata">

**Author:** ![jeff](https://forum.electromage.com/user_avatar/forum.electromage.com/jeff/32/3473_2.png) [@jeff](https://forum.electromage.com/u/jeff)\
**Post date:** [May 19, 2021, 3:41am UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/3 "2021-05-19T03:41:30Z")

</div>

Hey @Nick_W

I believe ZRanger1 [edit: Nope! Wizard] made the pattern in the library called “Example: Smooth Speed Slider” which does this. It’s compact enough that I’ll include it here:

> **Example: Smooth Speed Slider**
>
> ```javascript
> /*
> This pattern is based on the default scrolling rainbow and has a slider to control speed.
> It uses an accumulation based on delta instead of time() so that changes in speed do not cause the animation to jump.
> The downsides is slightly more code, and this pattern won't be synchronized with other Pixelblazes through firestorm.
> */
> 
> var speedRange = 1/1000 // this scales the milliseconds back to a usable range. shown here, the max rate is 1Hz
> var speed = speedRange // controlled by slider
> 
> export function sliderSpeed(s) {
> speed = s*s * speedRange // square it to give better control at lower values, then scale it
> }
> 
> var t1
> export function beforeRender(delta) {
> t1 = (t1 + delta * speed) % 1 // accumulate time in t1, and wrap it using modulus math to keep it between 0-1
> }
> 
> export function render(index) {
> h = t1 + index/pixelCount
> s = 1
> v = 1
> hsv(h, s, v)
> }
> 
> ```

Here’s another approach I use often, which is what I think Scruffy was going to narrow in on with the “delta of” concept:

> **Example: Time Offsets**
>
> ```javascript
> var duration = 2, t1Offset = time(duration / 65.535)
> 
> export function sliderSpeed(_v) {
> var oldDuration = duration
> duration = 10 / (1 + 9 * _v) // Period from 1 to 10 seconds
> t1Offset += time(oldDuration / 65.535) - time(duration / 65.535) + 1
> t1Offset %= 1
> } 
> 
> export function beforeRender(delta) {
> t1 = (time(duration / 65.535) + t1Offset + 1) % 1
> }
> 
> export function render(index) {
> hsv(0, 1, index == floor(t1 * pixelCount))
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 19, 2021, 12:51pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/4 "2021-05-19T12:51:01Z")

</div>

actually, my original idea had some issues (but I like the above solution), but when I saw @zranger1 's solution, which didn’t use time() at all, I realized there was a solution which did, and doesn’t need the delta:

```
export var speed, x, y, z
export function sliderSpeed(v) {
  speed = v*32700
}

export function beforeRender() {
  x = time(speed) // pulled out only for debug
  y = (x + y)%1 // replace x with time(speed) directly for less variables
  z = wave(y)
  // 
}

export function render(index) {
  h = z + index/pixelCount
  s = 1
  v = 1
  hsv(h, s, v)
}

```

This works with wave(), triangle(), and anything else you want to use.  
Kudos to @zranger for the idea to use mod and thus wrap, which makes it behave as a 0…1 (which means you can treat it like a time() itself).

Sliding the slider doesn’t cause any jump (unless you slide it to very fast/small, which could be limited in the slider)

I still think there is a solution where we can make it ‘accelerate’ (or decelerate) from speed A to speed B smoothly, but that’s for another day.

I just added a version of the above to the matrix arrayless KITT, to stop it from jumping around when you adjust the speed slider, and it’s absolutely an improvement.

Thanks @Nick_W for asking about this!

---

<div class="post-metadata">

**Author:** ![zranger1](https://forum.electromage.com/user_avatar/forum.electromage.com/zranger1/32/301_2.png) [@zranger1](https://forum.electromage.com/u/zranger1)\
**Post date:** [May 19, 2021, 2:54pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/5 "2021-05-19T14:54:02Z")

</div>

I can’t take credit for this excellent idea – I’m pretty sure it was @wizard who posted the Smooth Speed Slider example.

---

<div class="post-metadata">

**Author:** ![Nick\_W](https://forum.electromage.com/letter_avatar_proxy/v4/letter/n/958977/32.png) [@Nick\_W](https://forum.electromage.com/u/Nick_W)\
**Post date:** [May 19, 2021, 4:29pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/6 "2021-05-19T16:29:59Z")

</div>

I have tried all 3 of these ‘smooth speed’ sliders.

The first two (delta and time offset) work well.

@Scruffynerf 's version seems the simplest, but I can’t get it to work at all.  
I’ll play with it a bit more…

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 19, 2021, 5:10pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/7 "2021-05-19T17:10:49Z")

</div>

A few tips to making mine work (based on my own playing with it)

1. the value passed to speed needs to be relatively high. If your slider variable is low, multiply it by a lot (10000?) inside the time()  
Too fast a cycle and it’ll add too fast. You want a long cycle, for tiny increases to y.

[added - this was my goof: it ONLY works while it’s tiny, as the time value gets bigger, it breaks. I didn’t test this enough, I failed hard here.]

1. you have to put the main addition inside of before\_render. It won’t work inside the slider (only called when slider moves?) or main render (called too often), as it needs to keep adding the value time(speed) to y (%1), and then you can treat y as if it was a smooth running time() so wrap it in a wave/triangle/etc

I’ll definitely be using this in the future. I didn’t realize how many patterns don’t like their sliders adjusted. I mean they work, but they feel jarring when you adjust them.

Still researching bezier curve easing (which would be awesome) as that could make transitions even smoother, but way more work for very little payoff in 99% of the cases.

---

<div class="post-metadata">

**Author:** ![Nick\_W](https://forum.electromage.com/letter_avatar_proxy/v4/letter/n/958977/32.png) [@Nick\_W](https://forum.electromage.com/u/Nick_W)\
**Post date:** [May 19, 2021, 5:27pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/8 "2021-05-19T17:27:19Z")

</div>

This is my version:

```auto
//Smooth Speed Nick version
export var speed // controlled by slider

export function sliderSpeed(s) {
  speed = 1 / (1 + 99 * s)
  w = time(speed)
}

var t1
export function beforeRender() {
  x = time(speed)
  t1 = (t1 + (x-w)) % 1 // accumulate time in t1, and wrap it using modulus math to keep it between 0-1
  w = x
}

export function render(index) {
  h = t1 + index/pixelCount
  s = 1
  v = 1
  hsv(h, s, v)
}

```

---

<div class="post-metadata">

**Author:** ![Nick\_W](https://forum.electromage.com/letter_avatar_proxy/v4/letter/n/958977/32.png) [@Nick\_W](https://forum.electromage.com/u/Nick_W)\
**Post date:** [May 19, 2021, 5:39pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/9 "2021-05-19T17:39:29Z")

</div>

> [@Scruffynerf](#):
>
> you have to put the main addition inside of before\_render. It won’t work inside the slider (only called when slider moves?) or main render (called too often), as it needs to keep adding the value time(speed) to y (%1), and then you can treat y as if it was a smooth running time() so wrap it in a wave/triangle/etc

I still don’t understand this.  
Say x (time(speed)) is 0.25 for example, on first loop, y = (0.25 +0) % 1 ie 0.25.  
On the next loop, x is now 0.25001, so y = (0.25001 + 0.25) % 1 ie 0.50001  
Next loop, x is 0.25002, so y = (0.25002 + 0.50001) % 1 ie 0.75003  
etc.

This is my problem - you are adding y to itself, so, y is not a smooth running time. Am I missing something?

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 19, 2021, 6:14pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/10 "2021-05-19T18:14:52Z")

</div>

Ok, upon review, I dun goofed. By adding time() as I did in very small increments, it worked, but as values increased, it sped up incorrectly, which was entirely wrong. Now Fixed. My bad for not fully testing, I didn’t pay attention when the slider was too high to notice.

Thanks @jeff for suggestion of visualising one pixel, rather than the spectrum.

Correct code:

```
export var speed, y, z, h // exports for debugging
var tuning = 500 // scaling factor 

export function sliderSpeed(v) {
  speed = v / tuning 
  // 0..1 speed divided by tuning for scale (SMALL increments)
  // with the above tuning, speed goes from 0 to .0002, very small
}

export function beforeRender() {
  y = (speed + y)%1
  // y is now incremented slightly by speed before each render cycle, 
  // and stays within 0..1
  z = wave(y) 
  // because y is really a smooth sawtooth, wave() works as expected.
}

export function render(index) {
  h = z + index/pixelCount - 1 // color cycles
  // h = 1
  // ^ uncomment to make solid color
  s = 1
  v = (index == floor(z*pixelCount))  
  // only light one moving pixel, based on z (only one will be 1, rest will be 0)
  hsv(h, s, v)
}

```

the extra (and unneeded) time() causes the problem. I still want to use time() and will play with that more. @wizard’s [since Zranger disclaimed the code] original version is very similar, but also adds in delta to the increment value, so that it better handles framerate differences.

---

<div class="post-metadata">

**Author:** ![wizard](https://forum.electromage.com/user_avatar/forum.electromage.com/wizard/32/4_2.png) [@wizard](https://forum.electromage.com/u/wizard)\
**Post date:** [May 19, 2021, 7:08pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/11 "2021-05-19T19:08:16Z")

</div>

@Nick_W,  
Nice work! It looks like you are maintaining the phase, and incrementing by the corrected delta. That would work as well if you move the phase detection stuff to the slider, less math for beforeRender.

Here’s my take on it:

```auto
/*
The time(interval) function will return very different values for even small changes to interval. This
can cause animations to jump around if the interval used is changed e.g. through a slider.

This pattern shows a way to correct for that by measuring the phase difference when making changes to the interval.

The benefit of this method is that the interval can be changed without causing "jumps" in animation.
Since it still uses time() instead of delta, it can be synchronized with other Pixelblaze devices on the network, 
as long as they share the same interval and phase state.

*/

export var interval = .1 //aka "speed" to be controlled via a slider
export var phase = 0 //keep track of a phase correction factor

export function sliderConsistentSpeed(v) {
  var p1 = time(interval) //measure the current interval's value
  interval = v*v + .001
  var p2 = time(interval) //measure the new interval's value
  //calculate the phase difference between these
  phase = (1 + phase + p1 - p2) % 1
}

function phaseTime(interval, phase) {
  return (time(interval) + phase) % 1
}

export function beforeRender(delta) {
  t1 = phaseTime(interval, phase)
}

export function render(index) {
  h = t1 + index/pixelCount
  s = 1
  v = 1
  hsv(h, s, v)
}

```

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 19, 2021, 7:11pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/12 "2021-05-19T19:11:23Z")

</div>

Here I was saying to myself: it’s a phase difference, as you change the wavelength, there’s got to be a good way to do that… And you posted it as I was refreshing myself on the math. Nice.

---

<div class="post-metadata">

**Author:** ![Nick\_W](https://forum.electromage.com/letter_avatar_proxy/v4/letter/n/958977/32.png) [@Nick\_W](https://forum.electromage.com/u/Nick_W)\
**Post date:** [May 20, 2021, 1:38pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/13 "2021-05-20T13:38:49Z")

</div>

What about this:

```auto
//Smooth Speed Nick version II
export var speed
export function sliderSpeed(s) {
  speed = 1 / (1 + 99 * s)
}

var ts, p, prev_i
function smoothTime(interval) {
  /*
  time() function to smooth out changes in interval
  ts is time smooth, p is phase, prev_i is previous interval
  */
  x = time(prev_i)
  ts = (1+ ts + x - p) % 1 // accumulate time in ts, and wrap it using modulus math to keep it between 0-1
  p = (interval == prev_i) ? time(prev_i) : time(interval)
  prev_i = interval
  return ts
}

export function beforeRender() {
  t1 = smoothTime(speed)
}

export function render(index) {
  h = t1 + index/pixelCount
  s = 1
  v = 1
  hsv(h, s, v)
}

```

The advantages of this approach:

- No functions in `sliderSpeed()` so that can remain unchanged
- `smoothTime()` is a drop in replacement for `time()`
- if variable `speed` is changed directly (by `setVars()` say), it still works - no need to use the slider
- will still sync with other PB’s as it uses `time()`

So just add the `smoothTime()` function (plus global vars) to your pattern, change `time()` to `smoothTime()` and there you go.

If you use more than one `time()` function in your pattern, you would have to duplicate `smoothTime()` also, but that seems a minor issue.

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 20, 2021, 3:48pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/14 "2021-05-20T15:48:00Z")

</div>

> [@Nick\_W](#):
>
> If you use more than one `time()` function in your pattern, you would have to duplicate `smoothTime()` also, but that seems a minor issue.

Really nice work. I will absolutely use something like this.

You can easily reuse that function for multiples if you pass more than one value into it, like a pointer to an array. I’ll flesh that out later.

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 20, 2021, 3:55pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/15 "2021-05-20T15:55:00Z")

</div>

> [@Nick\_W](#):
>
> `p = (interval == prev_i) ? time(prev_i) : time(interval)`

Is this line actually needed as written?

In one case those are identical, in the other those are different, so you can always take the different.

For those who don’t understand this line:  
The **conditional (ternary) operator** is the only JavaScript operator that takes three operands: a condition followed by a question mark (`?` ), then an expression to execute if the condition is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) followed by a colon (`:` ), and finally the expression to execute if the condition is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy).

So if they are equal, then prev\_i is the same as interval so then using interval is always correct.

---

<div class="post-metadata">

**Author:** ![Nick\_W](https://forum.electromage.com/letter_avatar_proxy/v4/letter/n/958977/32.png) [@Nick\_W](https://forum.electromage.com/u/Nick_W)\
**Post date:** [May 20, 2021, 4:31pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/16 "2021-05-20T16:31:56Z")

</div>

> [@Scruffynerf](#):
>
> Is this line actually needed as written?

Of course you are right - bit too close to the trees here. I have it down to:

```auto
export var phase, prev_i
function smoothTime(interval) {
  /*
  time() function to smooth out changes in interval
  prev_i is previous interval
  */
  p1 = time(prev_i)
  p2 = time(interval)
  prev_i = interval
  phase += p1 - p2
  return (p2 + phase) % 1
}

```

Might need some testing just to make sure phase doesn’t become some huge number or something. so far it works with my numbers.

---

<div class="post-metadata">

**Author:** ![Nick\_W](https://forum.electromage.com/letter_avatar_proxy/v4/letter/n/958977/32.png) [@Nick\_W](https://forum.electromage.com/u/Nick_W)\
**Post date:** [May 20, 2021, 5:16pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/17 "2021-05-20T17:16:41Z")

</div>

Question:  
How does synchronizing `time()` between PB’s work? ie will the `phase` offset between `smoothTime()` and `time()` matter?

They will both be changing at the same rate, but would have different values due to the phase offset applied to `smoothTime()`.

I was tinkering with a version where the `phase` value is reduced to 0 over a short span of time, but I’m not sure it’s necessary.

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 20, 2021, 6:37pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/18 "2021-05-20T18:37:35Z")

</div>

Answer: @wizard described the process here in this forum comment.

> [@A Firestorm of Pixelblaze - spread patterns and control via MIDI/OSC](https://forum.electromage.com/t/a-firestorm-of-pixelblaze-spread-patterns-and-control-via-midi-osc/1186/7):
>
> That’s pretty much it: the impact on patterns is synchronization of the time call results. It works like this: Once a second PB sends out a beacon broadcast. Firestorm, or a Pixelblaze in AP mode, will reply with a “timesync” packet which contains the time base (a 32 bit number in milliseconds) and will thus act as a time sync source. The python clients [[1]](https://github.com/zranger1/pixelblaze-client),[[2]](https://github.com/NickWaterton/Pixelblaze-Async) can act as time sync sources as well. The actual time base number doesn’t matter so much as long as it increments by 1 for every mill…

---

<div class="post-metadata">

**Author:** ![Nick\_W](https://forum.electromage.com/letter_avatar_proxy/v4/letter/n/958977/32.png) [@Nick\_W](https://forum.electromage.com/u/Nick_W)\
**Post date:** [May 20, 2021, 7:07pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/19 "2021-05-20T19:07:40Z")

</div>

So, if you want to have the same values reported by multiple PB’s for `smoothTime()` would you need to have `phase` reduce to 0 over time?

I came up with this:

```auto
export var phase, prev_i
function smoothTime(interval, delta) {
  /*
  time() function to smooth out changes in interval
  prev_i is previous interval
  delta is optional, if passed, will reduce phase offset to 0 after a few seconds
  */
  var smooth = 0.0002 * delta //can't be smaller than 0.0001
  phase += (phase>smooth) ? -smooth : (phase<-smooth) ? smooth : -phase
  var p1 = time(prev_i), p2 = time(interval)
  prev_i = interval
  return (p2 + (phase += (p1 - p2))) % 1
}

export function beforeRender(delta) {
  t1 = smoothTime(speed, delta)
}

```

If you don’t pass `delta`, `smoothTime()` works as normal, however if you pass `delta`, then `smoothTime()` reduces the phase offset to 0 in some period of time depending on the frame rate.

Or is this a pointless complication…

---

<div class="post-metadata">

**Author:** ![Scruffynerf](https://forum.electromage.com/letter_avatar_proxy/v4/letter/s/34f0e0/32.png) [@Scruffynerf](https://forum.electromage.com/u/Scruffynerf)\
**Post date:** [May 21, 2021, 3:52pm UTC](https://forum.electromage.com/t/smooth-speed-slider/1249/20 "2021-05-21T15:52:28Z")

</div>

Not pointless. I can imagine cases where adjusting the slider causes “smart behavior” in it’s change. What that behavior needs to be depends greatly on the context.

It’s a case for easing.

But which easing formula we use depends on the usage.  
Here’s a bundle of handy formulas, all of which are easily replaceable.

> <https://github.com/danro/jquery-easing/blob/master/jquery.easing.js>

So making the phase shift reduce via easing, with the actual change being a function would allow this to be infinitely flexible.

Easing formulas above uses these variables:

t: current time (this is based on delta, but accumulated, relative to total duration, in a 0…1 range)  
b: beginning value (this is our current/starting phase value)  
c: change in value (this is always zero phase, in this use case, as we want to reduce phase smoothly)  
d: duration (this is how fast we want to return to zero)

Added:  
Excellent Walk thru and simplify of the above for specific cases [Improved Easing Functions](https://joshondesign.com/2013/03/01/improvedEasingEquations)

[Next page](https://forum.electromage.com/t/smooth-speed-slider/1249.md?page=2)
