Source: effects/audealize.js

/*
audealize.js: implements a high-level audio effect node in Web Audio API. To use it, simply instantiate the Web Audio Node in your Web Audio graph, and give a reverb word or an eq word.

Depends: reverb.js, equalizer.js, data.js, descriptor.js
*/

/**
 * <b>The Audealize AudioNode </b>(See {@tutorial gettingstarted}) <br>
 *
 * Enables semantic control of EQ and reverb effects <br><br>
 *
 * To use, instantiate the node in your web audio graph, then set
 * {@link Audealize~eq_descriptor} or {@link Audealize~reverb_descriptor} <br>
 * <br>
 *
 * This node can optionally look for synonyms if an unkown descriptor is given.
 * <br>
 * <i>To utilize this functionality, get an API key from
 * <a
 * href="http://words.bighugelabs.com/api.php">http://words.bighugelabs.com/api.php</a>
 * and pass as an argument to the
 * constructor.
 *
 *
 * @class
 * @name Audealize
 * @param {AudioContext} context - The Web Audio context
 * @param {string} api_key - (optional) API key for Thesaurus service provided
 * by
 * <a href="http://words.bighugelabs.com/api.php">words.bighugelabs.com</a>
 * (See {@tutorial synonyms})
 * @param {Object} opts - (optional) Initial vlaues for
 * eq_descriptor, reverb_descriptor, eq_amount, reverb_amount, eq_on, reverb_on
 */
function Audealize (context, api_key = '', opts = {}) {
  this.input = context.createGain();
  this.output = context.createGain();

  var curve = new Array(40).fill(0.0);
  this.eq = new Equalizer(context, { 'curve': curve });

  this.reverb = new Reverb(context);

  this.api_key = api_key || null;

  this.parameters = new Object();
  this.parameters.eq_descriptor = opts.eq_descriptor || 'bright';
  this.parameters.reverb_descriptor = opts.reverb_descriptor || 'crisp';
  this.parameters.eq_amount = opts.eq_amount || 1;
  this.parameters.reverb_amount = opts.reverb_amount || 0.7;
  this.parameters.eq_on = opts.eq_on || true;
  this.parameters.reverb_on = opts.reverb_on || true;

  // start out dry
  this.reverb.wetdry = 0;

  this.input.connect(this.eq.input);
  this.eq.connect(this.reverb.input);
  this.reverb.connect(this.output);
}

Audealize.prototype = Object.create(null, {
  /**
   * Connect output of this node to the input of another AudioNode
   * @function
   * @name Audealize~connect
   * @param {AudioNode} dest - The node to connect to
   */
  connect: {
    value: function(dest) {
      this.output.connect(dest.input ? dest.input : dest);
    }
  },

  /**
   * Disconnect the output of this node
   * @function
   * @name Audealize~disconnect
   */
  disconnect: {value: function() { this.output.disconnect(); }},

  /**
   * The EQ {@link Descriptor}. <br>
   * Set with a string or {@link Descriptor}. Changes to this paramter will
   * cause the effect settings to be changed immediately to match. <br>
   * If set with a descriptor not present in the EQ dictionary, the node
   * will attempt to find synonyms in the dictionary. (See {@tutorial synonyms})
   * <br>
   * If none are found, the descriptor will revert to its previous value.
   * @member
   * @name Audealize~eq_descriptor
   * @type Descriptor
   */
  eq_descriptor: {
    get: function() {
      return new Descriptor(this.parameters.eq_descriptor, 'eq');
    },
    set: function(word) {
      word = word.word ? word.word : word.toLowerCase();

      if (word in descriptors['eq']) {
        console.log('(Audealize) Changed eq setting to ' + word);
        this.eq.curve = descriptors['eq'][word]['settings'];
        this.parameters.eq_descriptor = word;
      } else {
        var synonyms = this.get_synonyms(word);
        if (synonyms.length > 0) {
 
          for (var i in synonyms) {
            var syn = synonyms[i];
            if (syn in descriptors['eq']) {
              this.parameters.eq_descriptor = syn;
              this.eq.curve =
                descriptors['eq'][syn]['settings'];
              console.log('(Audealize) Found EQ synonym ' + syn);
              return;
            }
          }
        }
        console.log('(Audealize) Descriptor not found');
      }
    }
  },

  /**
   * The reverb {@link Descriptor}. <br>
   * Set with a string or {@link Descriptor}. Changes to this paramter will
   * cause the effect settings to be changed immediately to match. <br>
   * If set with a descriptor not present in the reverb dictionary, the node
   * will attempt to find synonyms in the dictionary.
   * (See {@tutorial synonyms}) <br>
   * If none are found, the descriptor will revert to its previous value.
   * @member
   * @name Audealize~reverb_descriptor
   * @type Descriptor
   */
  reverb_descriptor: {
    get: function() {
      return new Descriptor(this.parameters.reverb_descriptor, 'reverb');
    },
    set: function(word) {
      word = word.word ? word.word : word.toLowerCase();

      if (word in descriptors['reverb']) {
        this.reverb.settings = descriptors['reverb'][word]['settings'];
        this.reverb.wetdry = this.parameters.reverb_amount;
        this.parameters.reverb_descriptor = word;
        console.log('(Audealize) Changed reverb setting to ' + word);
      } else {
        var synonyms = this.get_synonyms(word);
        
        if (synonyms.length > 0) { 
          for (var i in synonyms) {
            var syn = synonyms[i];
            if (syn in descriptors['reverb']) {
              this.parameters.eq_descriptor = syn;
              this.eq.curve = descriptors['reverb'][syn]['settings'];
              console.log('(Audealize) Found reverb synonym ' + syn);
              return;
            }
          }
        }  
        console.log('(Audealize) Descriptor not found');
      }
    }
  },

  /**
   * The intensity of the EQ effect. <br>
   * Scales the gain values of each filter in the equalizer. <br>
   * Default = 1.0. A value of 0.0 means the EQ curve will be flat at 0dB. <br>
   * Negative values can be used to achieve the inverse effect of the
   * descriptor. (e.g. If eq_descriptor = 'bright' and eq_amount = -1, the sound
   * will the opposite of bright)
   * @member
   * @name Audealize~eq_amount
   * @type number
   */
  eq_amount: {
    get: function() { return this.parameters.eq_amount; },
    set: function(amount) {
      this.parameters.eq_amount = amount;
      this.eq.range = amount;
    }
  },

  /**
   * The ratio of reverb to dry signal. <br>
   * 1 = reverb only. 0 = dry signal only. <br>
   * Set with a number [0,1]
   * @member
   * @name Audealize~reverb_amount
   * @type number
   */
  reverb_amount: {
    get: function() { return this.parameters.reverb_amount; },
    set: function(amount) {
      amount = Math.max(amount, 1);
      amount = Math.min(amount, 0);
      this.parameters.reverb_amount = amount;
      this.reverb.wetdry = amount;
    }
  },

  /**
   * The on/off state of the eq effect. <br>
   * If true, EQ is enabled.
   * @member
   * @name Audealize~eq_on
   * @type boolean
   */
  eq_on: {
    get: function() { return this.parameters.eq_on; },
    set: function(on) {
      this.parameters.eq_on = on;
      if (on) {
        this.eq.range = this.parameters.eq_amount;
      } else {
        this.eq.range = 0;
      }
    }
  },

  /**
    * The on/off state of the reverb effect. <br>
    * If true, reverb is enabled.
    * @member
    * @name Audealize~reverb_on
    * @type boolean
    */
  reverb_on: {
    get: function() { return this.parameters.reverb_on; },
    set: function(on) {
      this.parameters.reverb_on = on;
      if (on) {
        this.reverb.wetdry = this.parameters.reverb_amount;
      } else {
        this.reverb.wetdry = 0;
      }
    }
  },

  // For internal use only
  get_synonyms: {
    value: function(word) {
      if (this.api_key == null) {
        return [];
      }
      console.log('(Audealize) Looking for synonyms of ' + word);

      // Thesaurus service provided by words.bighugelabs.com
      var url = 'http://words.bighugelabs.com/api/2/' + this.api_key + '/';
      word = word.replace(/' '/g, '%20');
      var fullurl = url + word + '/json';
      var response = '';

      $.ajax({
        url: fullurl,
        success: function (repl, status) {
          response = repl;
        },
        type: 'POST',
        dataType: 'json',
        async: false
      });  // .fail(function (x) { console.log(x) })

      var synonyms = [];

      for (var mainkey in response) { // part of speech
        for (var subkey in response[mainkey]) { // syn, sim, ant, etc..
          if (subkey !== 'ant') { // don't want to include antonyms
            for (var syn in response[mainkey][subkey]) {
              synonyms.push(response[mainkey][subkey][syn]);
            }
          }
        }
      }
      if (synonyms.length == 0) {
        console.log('(Audealize) No synonyms found');
      }
      return synonyms;
    }
  }
});