gibber-cc / gibberish

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

Get only declared properties of a Synth #22

Open KonVas opened 6 years ago

KonVas commented 6 years ago

I would like to get only the properties of saw and not of the Synth. Is that possible?

saw = Synth({
    waveform:'saw',
    attack:88,
    decay:44100, 
    release:0.6
}).connect();

I am using Object.keys(saw) thus it turns (as expected) => waveform | attack | decay | sustain | sustainLevel | release | useADSR | shape | triggerRelease | gain | pulsewidth | frequency | pan | antialias | panVoices | loudness | glide | saturation | filterMult | Q | cutoff | filterType | filterMode | isLow

charlieroberts commented 6 years ago

So, if I understand correctly, you're looking for a list of the oscillator properties separate from the envelope / filter properties? There are actually separate osc, env, and filter properties but these refer to genish.js objects which probably won't be very useful to you.

If you can give me a bit more info on why you need this maybe I can help...

KonVas commented 6 years ago

Hi, thanks for getting back. What I want to do is to be able to load the arguments of the Synths that I have declared. Like in the above example, right now I am getting everything. The reason I want to do that is because I would like to provide these on the app of the interface where user will be able to map data (via a dynamic table) to the parameters of the synths that I will define for use in the app.

On the screenshot below is what I am getting now in the headings of my table: screen shot 2017-12-21 at 12 26 21

What I would like to have ideally is this below (names of the arguments are just for the example.): screen shot 2017-12-20 at 13 41 11

So what I am looking is how to map specific arguments every time someone loads a new synth. I thought by declaring explicitly the arguments like this below would work:

saw = Synth({
    waveform:'saw',
    attack:88,
    decay:44100, 
    release:0.6
}).connect();

Instead, (as probably expected) when using Object.keys(saw) it gets all arguments including the ones you referring. I understand this might be out of the scope of the library, but I was wondering if there is a way in the library to call specific properties instead of getting everything from the object. It would be helpful to be able to get and map the arguments of the osc and env for now.

KonVas commented 6 years ago

I guess the only way to do it now is by making a function using regexp, would this be the only way to go on?

charlieroberts commented 6 years ago

Can you give me an ideal example of how your code would look if gibberish was setup the way you're looking for? I think that would help me figure out what is/isn't possible.

KonVas commented 6 years ago

Ideally I would like to be able to interact with specific parameters of a synth. This below will only allow to set the given parameters.

'click #matrix-input': function(event, template){
var selected = template.findAll("input[type=checkbox]:checked");
var label = $(event.target).attr('class');
var fieldValue = event.target.value; 
var modifier = { };
if(label !== ""){
if(_.contains (['attack', 'decay', 'sustain', 'release', 'gain', 'frequency'], label)){
modifier[label] = Number(fieldValue);
Session.set('matrix', modifier);
console.log(Session.get('matrix'));
            }
     }
}

This way I will be able to control the synth using this matrix as seen below: screen shot 2018-01-21 at 14 33 00

My question is how to interact only with this provided in the array if(_.contains([...]), how to pass the values from the table, now I am able to make an object with key value pair: Object { sustain: 3.59408 } everytime I click on the table a corresponding parameter screen shot 2018-01-21 at 14 44 58

In some other languages like SuperCollider I would do something like this: synth.set(Object.keys(modifier), Object.values(modifier)) to control each parameter.

charlieroberts commented 6 years ago

Yeah, I don't think there's a way to do what you want exactly. However, there is often a .defaults property on synthesis objects that provides more specific keys. If you knew a synth had an ADSR envelope and a biquad filter, you get their respective properties with Object.keys( ADSR.defaults ) and Object.keys( Filter12Biquad.defaults ). There's also a Gibberish.oscillators.defaults.

These really weren't intended for end-users, so they don't seem to be consistently implemented, but I thought I'd point them out just in case they might help... sorry I don't have better news!

KonVas commented 6 years ago

I see; Thanks for the tips. I managed to get it going and now the app looks much better. One more question if you don't mind. I am making separate range specifications using this below, which works okayish, but I am not sure I am using the appropriate range spec for each parameter. Could you help on this. scale-Value is just a ib that takes inputMin inputMax, outMin outMax values to create scalings of the input value.

let scaleValue = require('scale-value');

const specs = {
    attack: scaleValue(0, 1, 100, 44100),
    decay: scaleValue(0, 1, 100, 22050),
    sustain: scaleValue(0, 1, 100, 44100),
    release: scaleValue(0, 1, 1, 100),
    gain: scaleValue(0, 1, 0.1, 0.8),
    frequency: scaleValue(0, 1, 120.0, 1220.0),
    triggerRelease: scaleValue(0, 1, 0.1, 10)
};

export default specs;

The ranges above might look weird, is just some trial and error thing now, so I would appreciate some help on the nominal range specs, or any pointer on these issue.

charlieroberts commented 6 years ago

Sorry, just saw this now... these things are tricky. An attack stage on a slow moving sound could last a minute, for example, so specifying a maximum value doesn't make a lot of sense. I've had to do similar things in projects I've had and it's always been problematic.

Here's a possibly better set:

let scaleValue = require('scale-value');

const specs = {
    attack: scaleValue(0, 1, 10, 44100 * 10),
    decay: scaleValue(0, 1, 10, 22050 * 10),
    sustain: scaleValue(0, 1, 0, 44100 * 10),
    release: scaleValue(0, 1, 10, 44100 * 10),
    gain: scaleValue(0, 1, 0.0, 1),
    frequency: scaleValue(0, 1, 0, 1)
};

triggerRelease is a boolean; scaling probably doesn't make sense. I guess for many of these properties, you're just going to have to make a design decision and go with it.