diff options
Diffstat (limited to 'src/com/jsyn/unitgen/PinkNoise.java')
-rw-r--r-- | src/com/jsyn/unitgen/PinkNoise.java | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/com/jsyn/unitgen/PinkNoise.java b/src/com/jsyn/unitgen/PinkNoise.java new file mode 100644 index 0000000..84aa2f2 --- /dev/null +++ b/src/com/jsyn/unitgen/PinkNoise.java @@ -0,0 +1,128 @@ +/* + * Copyright 2009 Phil Burk, Mobileer Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.jsyn.unitgen; + +import com.jsyn.ports.UnitInputPort; +import com.jsyn.ports.UnitOutputPort; +import com.jsyn.util.PseudoRandom; + +/** + * Random output with 3dB per octave rolloff providing a soft natural noise sound. Generated using + * Gardner method. Optimization suggested by James McCartney uses a tree to select which random + * value to replace. + * + * <pre> + * x x x x x x x x x x x x x x x x + * x x x x x x x x + * x x x x + * x x + * x + * </pre> + * + * Tree is generated by counting trailing zeros in an increasing index. When the index is zero, no + * random number is selected. Author: Phil Burk (C) 1996 SoftSynth.com. + */ + +public class PinkNoise extends UnitGenerator implements UnitSource { + + public UnitInputPort amplitude; + public UnitOutputPort output; + + private final int NUM_ROWS = 16; + private final int RANDOM_BITS = 24; + private final int RANDOM_SHIFT = 32 - RANDOM_BITS; + + private PseudoRandom randomNum; + protected double prevNoise, currNoise; + + private long[] rows = new long[NUM_ROWS]; // NEXT RANDOM UNSIGNED 32 + private double scalar; // used to scale within range of -1.0 to +1.0 + private int runningSum; // used to optimize summing of generators + private int index; // incremented with each sample + private int indexMask; // index wrapped and ANDing with this mask + + /* Define Unit Ports used by connect() and set(). */ + public PinkNoise() { + addPort(amplitude = new UnitInputPort("Amplitude", UnitOscillator.DEFAULT_AMPLITUDE)); + addPort(output = new UnitOutputPort("Output")); + + randomNum = new PseudoRandom(); + + // set up for N rows of generators + index = 0; + indexMask = (1 << NUM_ROWS) - 1; + + // Calculate maximum possible signed random value. Extra 1 for white + // noise always added. + int pmax = (NUM_ROWS + 1) * (1 << (RANDOM_BITS - 1)); + scalar = 1.0 / pmax; + + // initialize rows + for (int i = 0; i < NUM_ROWS; i++) { + rows[i] = 0; + } + + runningSum = 0; + } + + @Override + public void generate(int start, int limit) { + double[] amplitudes = amplitude.getValues(); + double[] outputs = output.getValues(); + + for (int i = start; i < limit; i++) { + outputs[i] = generatePinkNoise() * amplitudes[i]; + } + } + + public double generatePinkNoise() { + index = (index + 1) & indexMask; + + // If index is zero, don't update any random values. + if (index != 0) { + // Determine how many trailing zeros in PinkIndex. + // This algorithm will hang of n==0 so test first + int numZeros = 0; + int n = index; + + while ((n & 1) == 0) { + n = n >> 1; + numZeros++; + } + + // Replace the indexed ROWS random value. + // Subtract and add back to RunningSum instead of adding all the + // random values together. Only one changes each time. + runningSum -= rows[numZeros]; + int newRandom = randomNum.nextRandomInteger() >> RANDOM_SHIFT; + runningSum += newRandom; + rows[numZeros] = newRandom; + } + + // Add extra white noise value. + int newRandom = randomNum.nextRandomInteger() >> RANDOM_SHIFT; + int sum = runningSum + newRandom; + + // Scale to range of -1.0 to 0.9999. + return scalar * sum; + } + + @Override + public UnitOutputPort getOutput() { + return output; + } +} |