Use Backend Service / Web Worker for Metronome?


#1

Hi!
I’ve built a metronome (the thing, that musicians use to hold the tempo - tick, tack, tick, tack) with Typescript / Angular2 / Nativescript (2.4) using the nativescript-sound plugin.

Unfortunately, the interval (time between the “ticks”) isn’t very consistent. Is there any possibility to fix it? I thought of Backend-Services / Web-Workers… But they can’t access the plugin (to create the tick-sound), right?

let sound = require("nativescript-sound");

export class MetronomeComponent{

        public metronome = sound.create("~/pages/metronome/audio/click.mp3"); // preload the audio file 

        // A button triggers the start()-function
        start(){
            this.stop(); // stop running ticks if needed
            this.tick(); // start the metronome
        }

        // Is it possible to relocate this function to the backend?
        public tick() {
                this.metronome.play();
                this.timer = setTimeout(this.tick.bind(this), 60000/this.interval);
        }

I’d appreciate your help!

Thx,
Tarek


#2

There are a couple of different plugins for this it looks like:


#3

I believe the OP meant the Workers, those already present in the NS runtimes.

@tarek, you have complete* access to the underlying native API (and thus plugins that access the native API) in JavaScript even on a Worker thread, you will just have to see/test whether the plugin runs alright on the Worker.


#4

@Pete.K @Nick
Thx for your answers. I tried really hard the last days, to implement the metronome as a worker.
So far, I could successfully play the sound through the plugin and even create a loop.

But I couldn’t find out, how to stop the loop:

myApp.ts

        startMetronome(){            
            var worker = new Worker('./workers/worker');
            worker.postMessage({ tempo: 120 });
            worker.onmessage = function(msg) {
                if (msg.data.success) {
                console.log("WILL NEVER REACH THIS POINT...");
                worker.terminate();
            } else {
                ...
        }

worker.js

require('globals'); // necessary to bootstrap tns modules on the new thread
var soundNs = require("nativescript-sound");
var metronome = soundNs.create("~/pages/metronome/audio/click.mp3");

onmessage = function(msg) {
    var request = msg.data;
    var tempo = request.tempo;

    var result = timeout(tempo);

    var msg = result !== undefined ? { success: true, src: result } : { }

    postMessage(msg);
}

function timeout(tempo) {
    setTimeout(function () {
        metronome.play();
        return timeout(tempo);
    }, 60000/tempo);
}

It just goes on and on. I tried to create a public worker in myApp.ts, so I could use this.worker.terminate();. Unfortunately, this isn’t possible.

I hope someone has an idea about how to stop the infinite worker loop…
(Start-Button to start the worker loop, Stop-Button to terminate the worker loop).


#5

I initialized the worker in the constructor and now it even works with this.worker.
Problem solved :slight_smile:


#6

I’d suggest that you instantiate just 1(2) worker(s) and delegating playing sound to them instead of terminating them every time the sound is over. Creating a new Worker can be very expensive.


#7

But isn’t that what I’m doing right now? The loop is technically endless and 1 Worker is being used for this loop, until it gets shutdown by the Stop-Button.


#8

I read through the lines, you are correct.