text: //
  //  AudioSourceNoise.h
  //  hifi
  //
  //  Created by Craig Hansen-Sturm on 9/1/14.
  //  Copyright 2014 High Fidelity, Inc.
  //
  //  Distributed under the Apache License, Version 2.0.
  //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
  //
  //  Adapted from code by Phil Burk http://www.firstpr.com.au/dsp/pink-noise/
  //
  
  #ifndef hifi_AudioSourceNoise_h
  #define hifi_AudioSourceNoise_h
  
  template< const uint16_t N = 30>
  class AudioSourceNoise
  {
      static const uint16_t _randomRows = N;
      static const uint16_t _randomBits = 24;
      static const uint16_t _randomShift = (sizeof(int32_t) * 8) - _randomBits;
      
      static uint32_t _randomSeed;
      
  	int32_t _rows[_randomRows];
  	int32_t _runningSum; // used to optimize summing of generators.
  	uint16_t _index; // incremented each sample.
  	uint16_t _indexMask; // index wrapped by ANDing with this mask.
  	float32_t _scale; // used to scale within range of -1.0 to +1.0
      
      static uint32_t generateRandomNumber() {
          _randomSeed = (_randomSeed * 196314165) + 907633515;
          return _randomSeed >> _randomShift;
      }
      
  public:
      AudioSourceNoise() {
          initialize();
      }
      
      ~AudioSourceNoise() {
          finalize();
      }
      
      void initialize() {
          memset(_rows, 0, _randomRows * sizeof(int32_t));
          
          _runningSum = 0;
          _index = 0;
          _indexMask = (uint16_t)((1 << _randomRows) - 1);
          _scale = 1.0f / ((_randomRows + 1) * (1 << (_randomBits - 1)));
      }
      
      void finalize() {
      }
      
      void reset() {
          initialize();
      }
      
      void setParameters(void) {
      }
      
      void getParameters(void) {
      }
      
      void render(AudioBufferFloat32& frameBuffer) {
          
          uint32_t randomNumber;
          
          float32_t** samples = frameBuffer.getFrameData();
          for (uint32_t i = 0; i < frameBuffer.getFrameCount(); ++i) {
              for (uint32_t j = 0; j < frameBuffer.getChannelCount(); ++j) {
                  
                  _index = (_index + 1) & _indexMask; // increment and mask index.
                  if (_index != 0) { // if index is zero, don't update any random values.
                      
                      uint32_t numZeros = 0; // determine how many trailing zeros in _index
                      uint32_t tmp = _index;
                      while ((tmp & 1) == 0) {
                          tmp >>= 1;
                          numZeros++;
                      }
                      // replace the indexed _rows random value. subtract and add back to _runningSum instead
                      // of adding all the random values together. only one value changes each time.
                      _runningSum -= _rows[numZeros];
                      randomNumber = generateRandomNumber();
                      _runningSum += randomNumber;
                      _rows[numZeros] = randomNumber;
                  }
                  
                  // add extra white noise value and scale between -1.0 and +1.0
                  samples[j][i] = (_runningSum + generateRandomNumber()) * _scale;
              }
          }
      }
  };
  
  typedef AudioSourceNoise<> AudioSourcePinkNoise;
  
  #endif // AudioSourceNoise_h
  
  