<?xml version="1.0"?>
<!DOCTYPE ladspa SYSTEM "ladspa-swh.dtd">
<?xml-stylesheet href="ladspa.css" type="text/css"?>

<ladspa>
  <global>
    <meta name="maker" value="Andy Wingo &lt;wingo at pobox dot com&gt;"/>
    <meta name="copyright" value="GPL"/>
    <meta name="properties" value="HARD_RT_CAPABLE"/>
    <code><![CDATA[
      #include "random-taus88.h"
      #include "clz.h"
      #define MIN(x,y) (x < y ? x : y)
      #define MAX(x,y) (x > y ? x : y)
    ]]></code>
  </global>

  <!-- ******   WHITE-NOISE   ****** -->

  <plugin label="white_noise" id="23" class="NoisePlugin">
    <name>White Noise</name>
    <p>Samples are evenly distributed between -1.0 and +1.0.</p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      rt88_init (&random_state, (uint32_t)rand());
    ]]></callback>
    
    <callback event="run"><![CDATA[
      GET_RANDOM (random_state);

      while (sample_count--)
        *(out++) = rt88_frand2_3 (&s1, &s2, &s3);

      PUT_RANDOM (random_state);
      plugin_data->random_state = random_state;
    ]]></callback>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="random_state" type="rt88_state" />
  </plugin>

  <!-- ******   CLIP-NOISE   ****** -->

  <plugin label="clip_noise" id="24" class="NoisePlugin">
    <name>Clipping Noise</name>
    <p>Samples are either -1.0 or +1.0.</p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      rt88_init (&random_state, (uint32_t)rand());
    ]]></callback>
    
    <callback event="run"><![CDATA[
      GET_RANDOM (random_state);

      while (sample_count--)
        *(out++) = rt88_fcoin_3 (&s1, &s2, &s3);

      PUT_RANDOM (random_state);
      plugin_data->random_state = random_state;
    ]]></callback>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="random_state" type="rt88_state" />
  </plugin>

  <!-- ******   GRAY-NOISE   ****** -->

  <plugin label="gray_noise" id="25" class="NoisePlugin">
    <name>Gray Noise</name>
    <p>
      Generates noise which results from flipping random bits in a word. This
      type of noise has a high RMS level relative to its peak to peak level. The
      spectrum is emphasized towards lower frequencies.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      rt88_init (&random_state, (uint32_t)rand());
      counter = 0;
    ]]></callback>
    
    <callback event="run"><![CDATA[
      GET_RANDOM (random_state);

      while (sample_count--) {
        counter ^= 1L << (rt88_trand_3 (&s1, &s2, &s3) & 31);
        *(out++) = counter * 4.65661287308e-10f;
      }

      PUT_RANDOM (random_state);
      plugin_data->random_state = random_state;
      plugin_data->counter = counter;
    ]]></callback>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="random_state" type="rt88_state" />
    <instance-data label="counter" type="int" />
  </plugin>

  <!-- ******   PINK-NOISE   ****** -->

  <plugin label="pink_noise" id="26" class="NoisePlugin">
    <name>Pink Noise</name>
    <p>
      Generates noise whose spectrum falls off in power by 3 dB per octave. This
      gives equal power over the span of each octave.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      rt88_init (&random_state, (uint32_t)rand());
      {
	int32_t total = 0;
        int i;

        GET_RANDOM (random_state);

        dice = calloc (sizeof(uint32_t), 16);

	for (i=0; i<16; i++) {
          uint32_t newrand = rt88_trand_3 (&s1, &s2, &s3) >> 13;
          total += newrand;
          dice[i] = newrand;
        }

        PUT_RANDOM (random_state);
      }
    ]]></callback>
    
    <callback event="run"><![CDATA[
      uint32_t counter, prevrand, newrand, ifval;
      int k;

      GET_RANDOM (random_state);

      while (sample_count--) {
        counter = rt88_trand_3 (&s1, &s2, &s3); // Magnus Jonsson's suggestion.
        newrand = counter >> 13;
        k = (CTZ (counter)) & 15;
        prevrand = dice[k];
        dice[k] = newrand;
        total += (newrand - prevrand);
        newrand = rt88_trand_3 (&s1, &s2, &s3) >> 13;
        ifval = (total + newrand) | 0x40000000;
        *(out++) = (*(float*)&ifval) - 3.f;
      }

      PUT_RANDOM (random_state);
      plugin_data->random_state = random_state;
      plugin_data->total = total;
    ]]></callback>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="random_state" type="rt88_state" />
    <instance-data label="total" type="int32_t" />
    <instance-data label="dice" type="int32_t*" />
  </plugin>

  <!-- ******   BROWN-NOISE   ****** -->

  <plugin label="brown_noise" id="27" class="NoisePlugin">
    <name>Brown Noise</name>
    <p>
      Generates noise whose spectrum falls off in power by 6 dB per octave. This
      gives more power to the low range.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      rt88_init (&random_state, (uint32_t)rand());
      level = rt88_frand2 (&random_state);
    ]]></callback>
    
    <callback event="run"><![CDATA[
      float z = level;
      GET_RANDOM (random_state);

      while (sample_count--) {
        z += rt88_frand8_3 (&s1, &s2, &s3);
        if (z > 1.f)
          z = 2.f - z;
        else if (z < -1.f)
          z = -2.f - z;
        *(out++) = z;
      }

      PUT_RANDOM (random_state);
      plugin_data->random_state = random_state;
      plugin_data->level = z;
    ]]></callback>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="random_state" type="rt88_state" />
    <instance-data label="level" type="float" />
  </plugin>

  <!-- ******   DUST   ****** -->

  <plugin label="dust" id="28" class="NoisePlugin">
    <name>Dust</name>
    <p>
      Generates random impulses from 0 to +1.0.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      rt88_init (&random_state, (uint32_t)rand());
      last_density = thresh = scale = 0;
      sample_rate = s_rate;
    ]]></callback>
    
    <callback event="run"><![CDATA[
      float z;
      GET_RANDOM (random_state);

      if (density != last_density) {
        thresh = density / sample_rate;
        scale = thresh > 0.f ? 1.f / thresh : 0.f;
        plugin_data->thresh = thresh;
        plugin_data->scale = scale;
        plugin_data->last_density = density;
      }

      while (sample_count--) {
        z = rt88_frand_3 (&s1, &s2, &s3);
        *(out++) = z < thresh ? z * scale : 0.f;
      }

      PUT_RANDOM (random_state);
      plugin_data->random_state = random_state;
    ]]></callback>

    <port label="density" dir="input" type="control" hint="sample_rate,default_440,logarithmic">
      <name>Density</name>
      <p>The average density of the impulses, in Hz.</p>
      <range min="0" max="1"/>
    </port>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="random_state" type="rt88_state" />
    <instance-data label="sample_rate" type="int" />
    <instance-data label="thresh" type="float" />
    <instance-data label="scale" type="float" />
    <instance-data label="last_density" type="float" />
  </plugin>

  <!-- ******   DUST2   ****** -->

  <plugin label="dust2" id="29" class="NoisePlugin">
    <name>Dust</name>
    <p>
      Generates random impulses from -1.0 to +1.0.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      rt88_init (&random_state, (uint32_t)rand());
      last_density = thresh = scale = 0;
      sample_rate = s_rate;
    ]]></callback>
    
    <callback event="run"><![CDATA[
      float z;
      GET_RANDOM (random_state);

      if (density != last_density) {
        thresh = density / sample_rate;
        scale = thresh > 0.f ? 2.f / thresh : 0.f;
        plugin_data->thresh = thresh;
        plugin_data->scale = scale;
        plugin_data->last_density = density;
      }

      while (sample_count--) {
        z = rt88_frand_3 (&s1, &s2, &s3);
        *(out++) = z < thresh ? z * scale - 1.f : 0.f;
      }

      PUT_RANDOM (random_state);
      plugin_data->random_state = random_state;
    ]]></callback>

    <port label="density" dir="input" type="control" hint="sample_rate,default_440,logarithmic">
      <name>Density</name>
      <p>The average density of the impulses, in Hz.</p>
      <range min="0" max="1"/>
    </port>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="random_state" type="rt88_state" />
    <instance-data label="sample_rate" type="int" />
    <instance-data label="thresh" type="float" />
    <instance-data label="scale" type="float" />
    <instance-data label="last_density" type="float" />
  </plugin>

  <!-- ******   CRACKLE   ****** -->

  <plugin label="crackle" id="30" class="NoisePlugin">
    <name>Crackle</name>
    <p>
      A noise generator based on a chaotic function.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      y1 = 0.3f;
      y2 = 0.f;
    ]]></callback>
    
    <callback event="run"><![CDATA[
      float y0;

      while (sample_count--) {
        *(out++) = y0 = fabs (y1 * param - y2 - 0.05f);
        y2 = y1; y1 = y0;
      }

      plugin_data->y1 = y1;
      plugin_data->y2 = y2;
    ]]></callback>

    <port label="param" dir="input" type="control" hint="default_middle">
      <name>param</name>
      <p>
       A parameter of the chaotic function with useful values from just below
       1.0 to just above 2.0. Towards 2.0 the sound crackles.
      </p>
      <range min="0" max="3"/>
    </port>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="y1" type="float" />
    <instance-data label="y2" type="float" />
  </plugin>

  <!-- ******   LOGISTIC   ****** -->

  <plugin label="logistic" id="31" class="NoisePlugin">
    <name>Logistic</name>
    <p>
      A noise generator based on the logistical population function, which
      exhibits chaotic behavior.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      counter = -1;
      sample_rate = s_rate;
    ]]></callback>
    
    <callback event="run"><![CDATA[
      int remain;

      while (sample_count) {
        if (counter <= 0) {
          if (counter < 0) {
            y1 = starting_population;
          } else {
            y1 = param * y1 * (1.0 - y1); /* chaotic equation */
          }
          counter = (int)(sample_rate / MAX (frequency, .001f));
          counter = MAX (1, counter);
        }

        remain = MIN (counter, sample_count);
        counter -= remain;
        sample_count -= remain;
        while (remain--)
          *(out++) = y1;
      }

      plugin_data->y1 = y1;
      plugin_data->counter = counter;
    ]]></callback>

    <port label="param" dir="input" type="control" hint="default_high">
      <name>param</name>
      <p>
       A parameter of the logistic model, to multiply with pop * (1 - pop).
       Things get interesting when it's around 4.
      </p>
      <range min="0" max="5"/>
    </port>

    <port label="frequency" dir="input" type="control" hint="default_1,logarithmic">
      <name>Frequency</name>
      <p>The frequency at which the population is recalculated, in Hz.</p>
      <range min="0"/>
    </port>

    <port label="starting_population" dir="input" type="control" hint="default_high">
      <name>Starting Population</name>
      <p>
        The starting population. Should be between 0 and 1.
      </p>
      <range min="0" max="1"/>
    </port>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="y1" type="float" />
    <instance-data label="sample_rate" type="int" />
    <instance-data label="counter" type="int" />
  </plugin>

  <!-- ******   LF-CLIP-NOISE   ****** -->

  <plugin label="lf_clip_noise" id="32" class="NoisePlugin">
    <name>LF Clip Noise</name>
    <p>
      A noise generator outputting either -1 or +1. Recalculates the output at a
      set frequency.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      counter = 0;
      sample_rate = s_rate;
      rt88_init (&random_state, (uint32_t)rand());
    ]]></callback>
    
    <callback event="run"><![CDATA[

      while (sample_count--)
    ]]></callback>
    
    <callback event="run"><![CDATA[
      int remain;

      GET_RANDOM (random_state);

      while (sample_count) {
        if (counter <= 0) {
          y1 = rt88_fcoin_3 (&s1, &s2, &s3);
          counter = (int)(sample_rate / MAX (frequency, .001f));
          counter = MAX (1, counter);
        }

        remain = MIN (counter, sample_count);
        counter -= remain;
        sample_count -= remain;
        while (remain--)
          *(out++) = y1;
      }

      PUT_RANDOM (random_state);

      plugin_data->y1 = y1;
      plugin_data->counter = counter;
      plugin_data->random_state = random_state;
    ]]></callback>

    <port label="frequency" dir="input" type="control" hint="default_1,logarithmic">
      <name>Frequency</name>
      <p>The frequency at which the output is recalculated, in Hz.</p>
      <range min="0"/>
    </port>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="y1" type="float" />
    <instance-data label="sample_rate" type="int" />
    <instance-data label="counter" type="int" />
    <instance-data label="random_state" type="rt88_state" />
  </plugin>

  <!-- ******   LF-WHITE-NOISE   ****** -->

  <plugin label="lf_white_noise" id="33" class="NoisePlugin">
    <name>LF White Noise</name>
    <p>
      A noise generator outputting a random value between -1 and +1.
      Recalculates the output at a set frequency.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      counter = 0;
      sample_rate = s_rate;
      rt88_init (&random_state, (uint32_t)rand());
    ]]></callback>
    
    <callback event="run"><![CDATA[
      int remain;

      GET_RANDOM (random_state);

      while (sample_count) {
        if (counter <= 0) {
          y1 = rt88_frand2_3 (&s1, &s2, &s3);
          counter = (int)(sample_rate / MAX (frequency, .001f));
          counter = MAX (1, counter);
        }

        remain = MIN (counter, sample_count);
        counter -= remain;
        sample_count -= remain;
        while (remain--)
          *(out++) = y1;
      }

      PUT_RANDOM (random_state);

      plugin_data->y1 = y1;
      plugin_data->counter = counter;
      plugin_data->random_state = random_state;
    ]]></callback>

    <port label="frequency" dir="input" type="control" hint="default_1,logarithmic">
      <name>Frequency</name>
      <p>The frequency at which the output is recalculated, in Hz.</p>
      <range min="0"/>
    </port>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="y1" type="float" />
    <instance-data label="sample_rate" type="int" />
    <instance-data label="counter" type="int" />
    <instance-data label="random_state" type="rt88_state" />
  </plugin>

  <!-- ******   LF-SMOOTH-NOISE   ****** -->

  <plugin label="lf_smooth_noise" id="34" class="NoisePlugin">
    <name>LF Smooth Noise</name>
    <p>
      A noise generator outputting a random value between -1 and +1.
      Recalculates the output at a set frequency. Unlike LF White Noise, this
      generator interpolates between the output values to avoid a step change in
      the output.
    </p>
    <p>Based on work by James McCartney in SuperCollider.</p>
    
    <callback event="instantiate"><![CDATA[
      counter = 0;
      sample_rate = s_rate;
      rt88_init (&random_state, (uint32_t)rand());
    ]]></callback>
    
    <callback event="run"><![CDATA[
      int remain;

      GET_RANDOM (random_state);

      while (sample_count) {
        if (counter <= 0) {
          float next_level = rt88_frand2_3 (&s1, &s2, &s3);
          counter = (int)(sample_rate / MAX (frequency, .001f));
          counter = MAX (1, counter);
          plugin_data->slope = slope = (next_level - level) / counter;
        }

        remain = MIN (counter, sample_count);
        counter -= remain;
        sample_count -= remain;
        while (remain--) {
          *(out++) = level;
          level += slope;
        }
      }

      PUT_RANDOM (random_state);

      plugin_data->level = level;
      plugin_data->counter = counter;
      plugin_data->random_state = random_state;
    ]]></callback>

    <port label="frequency" dir="input" type="control" hint="default_1,logarithmic">
      <name>Frequency</name>
      <p>The frequency at which the output is recalculated, in Hz.</p>
      <range min="0"/>
    </port>

    <port label="out" dir="output" type="audio">
      <name>Output</name>
    </port>

    <instance-data label="level" type="float" />
    <instance-data label="slope" type="float" />
    <instance-data label="sample_rate" type="int" />
    <instance-data label="counter" type="int" />
    <instance-data label="random_state" type="rt88_state" />
  </plugin>
</ladspa>
