Sound + Non sound pattern

Hi @Asphalt.Astronaut,
Awesome!

Pixelblaze’s language is based off of JavaScript (ES6) syntax, but with a subset of the language features available. You won’t find many of the JavaScripty things there, while others are different. For example you call sin(a) instead of Math.sin(a), and array(size) instead of new Array(size). APIs like setTimeout, setInterval don’t exist yet, but I hope to add something similar in the future. The full list of supported features and APIs is available with the documentation just below the editor (scroll down on the page).

Another one of the differences is that all numbers in Pixelblaze are a 16.16 fixed-point numbers. This can handle values between -32,768 to +32,767 with fractional accuracy down to 1/65,536ths.

The beforeRender(delta) can be used to keep track of time passing. The delta parameter gives you the time that has elapsed in milliseconds since the last beforeRender call. You can accumulate that up to keep track of time.

Here’s a seconds (not milliseconds) setTimeout implementation that you can use:


// these variables hold data used by the timer functions
// put them at the top of your code
var maxTimers = 10 
var timerFns = array(maxTimers)
var timerTimes = array(maxTimers)

/**
 * Schedule a function to run after some time (in seconds) elapses.
 * If successful, a non-negative id is returned and can be used 
 * to cancel it using clearTimeout(id). Returns -1 on error.
 */
function setTimeout(fn, timeout) {
  var nextTimer = -1
  //find an empty timer slot
  for (var i = 0; i < maxTimers; i++) {
    if (!timerFns[i]) {
      nextTimer = i
      break
    }
  }

  if (nextTimer >= 0) {
    timerFns[nextTimer] = fn
    timerTimes[nextTimer] = timeout
  }
  return nextTimer
}

/**
 * Cancel a timeout by id
 */
function clearTimeout(id) {
  if (id >= 0) {
    timerFns[id] = false
  }
}

/**
 * Update timers based on elapsed time, and call any callbacks.
 * Call this from beforeRender(delta)
 */
function updateTimers(delta) {
  var seconds = delta/1000
  //check timers
  for (var i = 0; i < maxTimers; i++) {
    //see if there is a function for this slot
    if (timerFns[i]) {
      //reduce times until zero
      timerTimes[i] = max(0, timerTimes[i] - seconds)
      //see if timer is up
      if (timerTimes[i] == 0) {
        var fn = timerFns[i]
        //blank out this slot so we don't keep executing it and it can be reused
        timerFns[i] = false 
        fn() //run the function
      }
    }
  }
}

To use, you’ll call updateTimers(delta) inside your beforeRender implementation. You can register a function (or even a lambda) to run later, and cancel them. A common pattern is to cancel the old timer and re-schedule it every time an even occurs to know some time after the last one happened.

You could use this code, and fill out what you want to happen in stoppedHearingSound(). Call heardSound() every time your code detects sufficient sound to start/reset the timer.

function stoppedHearingSound() {
  //do something 30 seconds after the last time sound was heard here
}

var timerId = -1
function heardSound() {
  //cancel a previous timer if one was set
  if (timerId != -1)
    clearTimeout(timerId)
  //set a timer to trigger in 30 seconds
  timerId = setTimeout(() => {
    timerId = -1
    stoppedHearingSound();
  }, 30)
}
1 Like