gibber-cc / gibberish

Fast, JavaScript DSP library that creates JIT optimized audio callbacks using code generation techniques
387 stars 35 forks source link

How to represent a variable? #16

Closed abramhindle closed 7 years ago

abramhindle commented 7 years ago

My question is "If I have a value I want to share with the Gibberish network, how do I get it in there?". Here's an example:

var q = 0; // q will be set by some callbacks later
Mul(q, new Gibberish.Sine(440,1.0)).connect();
setInterval(function() { q = Math.random(); }, 100);

If we look at the generated code, the value of q rather than q itself is taken. I wasn't sure how I'd represent an a-rate signal in Gibberish so I did something like this:

Gibberish.Step = function() {
      Gibberish.extend(this, {
        name:'step',
        properties: {
            amp:1,
            value:0.0,
        },        
        callback : function(amp, value){ 
            return amp * value;
        },
    });
    this.init();
    this.oscillatorInit();
    this.processProperties(arguments);  
};
Gibberish.Step.prototype = Gibberish._oscillator;

Then I'd be able to do the following.

var q = new Gibberish.Step(1.0,0.0); // q will be set by some callbacks later
Mul(q, new Gibberish.Sine(440,1.0)).connect();
setInterval(function() { q.value = Math.random(); }, 100);

I understand that you're relying on JITing and you want to avoid calls to objects as much as possible, but is this Step the right thing to do? Does something like it already exist within Gibberish?

Alternatively if that functionality is missing, do you want it? It also seems quite ineffecient but w/o breaking scope it is hard to do otherwise.

charlieroberts commented 7 years ago

Hi Abram!

First, I recommend checking out the v3 branch; the library has been re-written from scratch and is greatly improved, both in terms of efficiency and architecture. I haven't formally released it yet, but you can play with it here: http://www.charlie-roberts.com/gibberish2

Here's how you would make a Var constructor in the new version:

g = Gibberish.genish

Var = initialValue => {
  const ugen = Object.create( Gibberish.prototypes.ugen )

  const graph = g.param( initialValue )

  return Gibberish.factory( ugen, graph, 'var' )
}

a = Var( 220 )

b = Sine({ frequency: a }).connect()

setInterval( ()=> a.graph.value = 220 + Math.random() * 880, 100 )

Behind the scenes Gibberish uses genish.js (http://www.charlie-roberts.com/genish). If you have time to learn a bit about genish, making ugens in the new version of Gibberish will make a lot more sense.

That said, your code example looks great for the current master branch of Gibberish! I'll point out that I think your solution is mostly needed when you want to access the same variable in multiple locations of the graph. For example, in any binop you can always change the values at audio rate using simple property lookup (e.g. binop[0], binop[1]). So:

var q = 1
// can you call .connect() with a Mul()? I can't even remember...
var m = Mul(q, new Gibberish.Sine(440,1.0)).connect();
setInterval(function() { m[0] = Math.random(); }, 100);

But again, if you want the variable to be referenced in multiple parts of the graph then you need a solution like you provided.

Sorry for the long response; hope it's helpful! - Charlie