![JAR search and dependency download from the Maven repository](/logo.png)
jm.audio.synth.Noise Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmusic Show documentation
Show all versions of jmusic Show documentation
JMusic - Java Music Library
The newest version!
/*
Copyright (C) 2000 Andrew Sorensen & Andrew Brown
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package jm.audio.synth;
import jm.audio.AOException;
import jm.audio.AudioObject;
import jm.audio.Instrument;
/**
* The Noise class contains various noise waveform generators,
* incluidng white noise and fractal noise.
*
* @author Andrew Brown
* @version 1.0, Sun Feb 25 18:42:52 2001
*/
public class Noise extends AudioObject {
//----------------------------------------------
// Attributes
//----------------------------------------------
/**
* Different noise type constants
*/
public static final int WHITE_NOISE = 0,
STEP_NOISE = 1,
SMOOTH_NOISE = 2,
BROWN_NOISE = 3,
FRACTAL_NOISE = 4,
GAUSSIAN_NOISE = 5,
WALK_NOISE = 6,
GENDYN_NOISE = 7;
// for fractal math
private static float sum;
private static float[] rg = new float[16];
private static int k, kg, ng, threshold;
private static int np = 1;
private static int nbits = 1;
private static int numbPoints = 48000; //number of notes
private static float nr = (float) (numbPoints);
private static float result;
private static int counter = 0;
/**
* A variable to choose different noise properties
* 0 = white noise
* 1 = low resolution (and frequency) noise
* 2 = smoothed noise
* 3 = brown noise
* 4 = fractal noise
* 5 = gaussian noise
* 6 = random walk noise
* 7 = gendyn noise (after Xenakis' stochastic synthesis)
*/
private int noiseType = 0;
private int noiseDensity = 10;
private float amp = 1.0f;
// for gaussian noise
private double standardDeviation = 0.25;
// for walk noise
private double mean = 0.0;
/**
* Current sample value of the random walk algorithm
*/
private float walkLastValue = 0.0f;
/**
* How large a jump from the current sample value is allowable
*/
private float walkStepSize = 0.3f;
/**
* The largest value a sample value can be in the random walk algorithm.
*/
private float walkMax = 1.0f;
/**
* The smallest value a sample value can be in the random walk algorithm.
*/
private float walkMin = -1.0f;
/**
* The number of steps of the same value before changing. Realted to frequency range of sound.
*/
private int walkNoiseDensity = 500;
/**
* Maintains a count of the number of samples processed
*/
private long walkDensityCounter = 0;
/**
* Will the denisty value vary as a random walk or remain stable.
*/
private boolean walkVaryDensity = true;
/**
* The smallest number of repeated sample values (quantise) for the walk density.
*/
private int walkNoiseDensityMin = 1; // one or larger.
/**
* The largest number of repeated sample values (quantise) for the walk density.
*/
private int walkNoiseDensityMax = 1500; // 1 or larger.
/**
* The size of the noise density change at each iteration.
*/
private int walkNoiseDensityStepSize = 100;
// gendyn noise variables
private java.util.Random RandomGenerator = new java.util.Random();
private int gendynAmpGranularity = 128;//50; // more or less quantisation noise
private double gendynPrevTime = 50;
private int gendynTimeMirror = 80;
private int gendynAmpMirror = 80;
private int tempAmpMirror;
private boolean ampMirrorUpdate = false;
/**
* The starting sample value for the wave
*/
private int gendynPointSize = 4;
private double[] gendynAmpArray = new double[gendynPointSize];
private double[] gendynTimeArray = new double[gendynPointSize];
private boolean pointSizeReset = false;
private int newPointSize;
private double gendynAmp0 = 0.0;
private int gendynIntArray[];
private double gendynIntArrayLength;
private int gendynIntArrayCounter = 0;
private double gendynTimeStepSize = 10.0;
private double maxGendynTimeStepSize = 100.0; // 75 // Xenakis would have this at 100
private double gendynAmpStepSize = 10.0;
private double maxGendynAmpStepSize = 100.0; // 10 // Xenakis would have this at 100
private int mirrorMax = 100;
/**
* Use a gaussian or normal random distribution
*/
private boolean gendynGaussian = false;
private double gendynPrimaryTimeStepSize = 10.0;
private double gendynPrimaryAmpStepSize = 10.0; //gendynAmpGranularity/10;
private int gendynPrimaryTimeMirror = 100;
private int gendynPrimaryAmpMirror = 100;
private int gendynInterpolation = 1; // linear = 1, coside = 2, square = 3
private boolean gendynGranularityUpdate = false;
private int tempGendynGranularity;
//----------------------------------------------
// Constructors
//----------------------------------------------
/**
* Returns a random sample value to each channel
*
* @param buffer The sample buffer.
*/
private float gnSampleVal;
private int gnj;
private int mgaCounter;
private double mgaInc;
private int index, jindex;
// the random walk function for gendyn noise
private double rwNewVal;
/**
* Default constructor
*
* @param Instrument the class instance 'this'
*/
public Noise(Instrument inst) {
this(inst, WHITE_NOISE);
}
//----------------------------------------------
// Methods
//----------------------------------------------
/**
* This constructor sets this object up as a noise generator
* allowing you to specify the type of noise
*
* @param Instrument the class instance 'this'
* @param sampleRate the sampling rate
*/
public Noise(Instrument inst, int noiseType) {
this(inst, noiseType, 44100);
}
/**
* This constructor sets this object up as a noise generator
* allowing you to specify the type of noise and sample rate
*
* @param Instrument the class instance 'this'
* @param sampleRate the sampling rate
* @param noiseType the flavour of noise to use
*/
public Noise(Instrument inst, int noiseType, int sampleRate) {
this(inst, noiseType, sampleRate, 1);
}
/**
* This constructor sets this object up as a noise generator
* with all parameters
*
* @param Instrument the class instance 'this'
* @param sampleRate the sampling rate
* @param noiseType the flavour of noise to use
* @param channels the number of channels to use
*/
public Noise(Instrument inst, int noiseType, int sampleRate, int channels) {
super(inst, sampleRate, "[WaveTable]");
this.noiseType = noiseType;
this.channels = channels;
// setup math for fractal noise
if (noiseType == FRACTAL_NOISE) setUpFractalMath();
// setup array for gendyn noise
if (noiseType == GENDYN_NOISE) makeGendynArray();
for (int i = 0; i < gendynPointSize; i++) {
gendynAmpArray[i] = 50;
}
}
/**
* Get the fixed amp of this Noise instance
*/
public float getAmp() {
return this.amp;
}
/**
* Set the fixed amp of this Noise instance
*
* @param amp Fixed value amplitude
*/
public void setAmp(float amp) {
this.amp = amp;
}
private void setUpFractalMath() {
// setup math for fractal noise
nr = nr / 2;
while (nr > 1) {
nbits++;
np = 2 * np;
nr = nr / 2;
}
for (kg = 0; kg < nbits; kg++) {
rg[kg] = (float) (Math.random());
}
}
public int work(float[] buffer) throws AOException {
int ret = 0; //the number of samples to return
// run the appropiate code for the chosen noise type
//System.out.println("noise = " + noiseType);
switch (this.noiseType) {
case WHITE_NOISE:
for (; ret < buffer.length; ) {
for (int j = 0; j < channels; j++) {
buffer[ret++] = (float) (Math.random() * 2.0 - 1.0) * amp;
}
}
;
break;
case BROWN_NOISE:
float prev0 = 0.0f;
float prev1 = 0.0f;
float prev2 = 0.0f;
float brownValue, current;
for (; ret < buffer.length; ) {
for (int j = 0; j < channels; j++) {
current = (float) (Math.random() * 2.0 - 1.0) * amp;
brownValue = (prev0 + prev1 + prev2 + current) / 4.0f;
buffer[ret++] = brownValue;
// update values
prev0 = prev1;
prev1 = prev2;
prev2 = current;
}
}
;
break;
case STEP_NOISE:
// low sample resolution noise (RandH noise)
// has greater energy in the low frequency spectrum
int density = this.noiseDensity;
float temp = (float) (Math.random() * 2.0 - 1.0) * amp;
for (; ret < buffer.length; ) {
for (int j = 0; j < channels; j++) {
if (ret % density == 0) temp =
(float) (Math.random() * 2.0 - 1.0) * amp;
buffer[ret++] = temp;
}
}
;
break;
case SMOOTH_NOISE:
// interpolated noise (RandI noise)
// has an even greater emphasis on low frrquency energy
density = this.noiseDensity;
temp = (float) (Math.random() * 2.0 - 1.0) * amp;
float temp2 = (float) (Math.random() * 2.0 - 1.0) * amp;
for (; ret < buffer.length; ) {
for (int j = 0; j < channels; j++) {
if ((ret + 1) % density == 0) {
buffer[ret++] = temp2;
temp = temp2;
temp2 = (float) (Math.random() * 2.0 - 1.0) * amp;
} else {
buffer[ret++] = temp +
((temp2 - temp) / density * (ret % density));
}
}
}
;
break;
case FRACTAL_NOISE:
for (; ret < buffer.length; ) {
for (int j = 0; j < channels; j++) {
if (counter % noiseDensity == 0) { //recalculate
threshold = np;
ng = nbits;
while (k % threshold != 0) {
ng--;
threshold = threshold / 2;
}
sum = 0;
for (kg = 0; kg < nbits; kg++) {
if (kg < ng) {
rg[kg] = (float) (Math.random());
}
sum += rg[kg];
}
result = (float) (((sum / nbits) - 0.17) * 2.85 - 1.0);
if (result > 1.0) result = (float) 1.0;
else if (result < -1.0) result = (float) -1.0;
}
counter++;
buffer[ret++] = result * amp;
}
if (counter > 67000) counter = 0;
}
break;
case GAUSSIAN_NOISE:
java.util.Random RNG = new java.util.Random();
float gaussValue;
for (; ret < buffer.length; ) {
for (int j = 0; j < channels; j++) {
gaussValue = (float) (RNG.nextGaussian() *
standardDeviation + mean);
if (gaussValue < -1.0f) gaussValue = -1.0f;
else if (gaussValue > 1.0f) gaussValue = 1.0f;
buffer[ret++] = gaussValue * amp;
}
}
;
break;
case WALK_NOISE:
for (; ret < buffer.length; ) {
for (int j = 0; j < channels; j++) {
buffer[ret++] = walkLastValue;
walkDensityCounter++;
if ((int) walkDensityCounter % walkNoiseDensity == 0) {
// update value
walkLastValue += (float) (Math.random()) * walkStepSize * 2.0f - walkStepSize;
while (walkLastValue > walkMax || walkLastValue < walkMin) {
if (walkLastValue > walkMax) walkLastValue -= (walkLastValue - walkMax) * 2.0f;
if (walkLastValue < walkMin) walkLastValue += (walkMin - walkLastValue) * 2.0f;
}
// vary the denisty value if required
if (walkVaryDensity) {
// a random walk of the denisty (root frequency)
walkNoiseDensity += (int) (Math.random() *
walkNoiseDensityStepSize * 2.0 - walkNoiseDensityStepSize);
if (walkNoiseDensity < walkNoiseDensityMin) walkNoiseDensity = walkNoiseDensityMin;
else if (walkNoiseDensity > walkNoiseDensityMax) walkNoiseDensity = walkNoiseDensityMax;
//System.out.println("change density to " + walkNoiseDensity);
}
}
}
}
break;
case GENDYN_NOISE:
gnSampleVal = 0.0f;
for (; ret < buffer.length; ) {
// System.out.println("array size " + gendynIntArray.length);
gnSampleVal = (gendynIntArray[gendynIntArrayCounter] / (float) gendynAmpGranularity - 0.5f) * 2.0f;
// clipping limter
if (gnSampleVal > 1.0) gnSampleVal = 1.0f;
else if (gnSampleVal < -1.0) gnSampleVal = -1.0f;
for (gnj = 0; gnj < channels; gnj++) {
// add next value from array
buffer[ret++] = gnSampleVal;
}
gendynIntArrayCounter++;
if (gendynIntArrayCounter >= (int) gendynIntArrayLength) makeGendynArray();
}
break;
default:
System.err.println(this.name + "jMusic error: Noise type "
+ noiseType + " not supported yet.");
System.exit(1);
}
return ret;
}
private void makeGendynArray() {
// calculate new step sizes - second level change Xenakis had
gendynTimeStepSize = randWalk(gendynTimeStepSize,
gendynPrimaryTimeStepSize,
gendynPrimaryTimeMirror, true);
if (Math.abs(gendynTimeStepSize) > maxGendynTimeStepSize)
gendynTimeStepSize = maxGendynTimeStepSize;
gendynAmpStepSize = randWalk(gendynAmpStepSize,
gendynPrimaryAmpStepSize,
gendynPrimaryAmpMirror, false);
if (Math.abs(gendynAmpStepSize) > maxGendynAmpStepSize)
gendynAmpStepSize = maxGendynAmpStepSize;
// calulate new break point values
//System.out.print("t1-");
for (index = 0; index < gendynPointSize; index++) {
gendynTimeArray[index] = Math.abs(randWalk(gendynTimeArray[index],
gendynTimeStepSize,
gendynTimeMirror, true));
// prevent zero time
if (gendynTimeArray[index] < 1.0) gendynTimeArray[index] = 1.0;
gendynAmpArray[index] = randWalk(gendynAmpArray[index],
gendynAmpStepSize,
gendynAmpMirror / 2 + 51, false);
}
//System.out.println(gendynTimeArray[0] + " " + gendynAmpArray[0] + " " +
// gendynTimeArray[1] + " " + gendynAmpArray[1] + " " +
// gendynTimeArray[2] + " " + gendynAmpArray[2] );
//
// interpolate int array
//
gendynIntArrayLength = 0;
for (index = 0; index < gendynPointSize; index++) {
gendynIntArrayLength += gendynTimeArray[index];
}
//System.out.println("length = " + gendynIntArrayLength);
gendynIntArray = new int[(int) gendynIntArrayLength];
mgaCounter = 0;
// stage 1
mgaInc = (gendynAmpArray[0] - gendynAmp0) / (double) gendynTimeArray[0];
//first - continuing from previous
for (jindex = 0; jindex < (int) gendynTimeArray[0]; jindex++) {
switch (gendynInterpolation) {
case 2:
// cos
double diff = (1.0 - (Math.cos(jindex / (double) gendynTimeArray[0] * 3.14) / 2.0 + 0.5)) *
(gendynAmpArray[0] - gendynAmp0);
gendynIntArray[mgaCounter++] = (int) ((gendynAmp0 + diff) /
100.0 * gendynAmpGranularity);
break;
case 1:
// linear
gendynIntArray[mgaCounter++] = (int) ((gendynAmp0 + mgaInc * jindex) /
100.0 * gendynAmpGranularity);
break;
case 3:
// square
gendynIntArray[mgaCounter++] = (int) (gendynAmp0 / 100.0 * gendynAmpGranularity);
}
}
// remainder
for (index = 1; index < gendynPointSize - 1; index++) {
mgaInc = (gendynAmpArray[index] - gendynAmpArray[index - 1]) / (double) gendynTimeArray[index];
for (jindex = 0; jindex < (int) gendynTimeArray[index]; jindex++) {
switch (gendynInterpolation) {
case 2:
double diff = (1.0 - (Math.cos(jindex / (double) gendynTimeArray[index] * 3.14) / 2.0 + 0.5)) *
(gendynAmpArray[index] - gendynAmpArray[index - 1]);
gendynIntArray[mgaCounter++] = (int) ((gendynAmpArray[index - 1] + diff) /
100.0 * gendynAmpGranularity);
break;
case 1:
// linear
//System.out.println("gendynPointSize = " + gendynPointSize + " gendynIntArray = " + gendynIntArray.length + " mgaCounter = " + mgaCounter);
gendynIntArray[mgaCounter++] = (int) ((gendynAmpArray[index - 1] + mgaInc * jindex) /
100.0 * gendynAmpGranularity);
break;
case 3:
// square
gendynIntArray[mgaCounter++] = (int) (gendynAmpArray[index - 1] /
100.0 * gendynAmpGranularity);
}
}
}
// keep last value to start next wave
gendynAmp0 = gendynAmpArray[gendynPointSize - 1];
// reset counter
gendynIntArrayCounter = 0;
// update numberof points?
if (pointSizeReset) resetPointSize();
// upadage granularity?
if (gendynGranularityUpdate) updateGranularity();
}
private double randWalk(final double prevVal, final double stepSize, final int mirror, final boolean timeWalk) {
rwNewVal = 0;
if (gendynGaussian) {
rwNewVal = prevVal + (RandomGenerator.nextGaussian() * stepSize);
} else rwNewVal = prevVal + (RandomGenerator.nextDouble() * stepSize * 2.0 - stepSize);
// keep inside range
if (timeWalk) {
if (stepSize == 0) {
rwNewVal = prevVal;
} else {
while (rwNewVal > mirror || rwNewVal < 0.0) {
if (rwNewVal > mirror) rwNewVal = mirror - (rwNewVal - mirror);
if (rwNewVal < 0.0) rwNewVal = (rwNewVal / 2.0 * -1.0);
}
}
// avoid less than (1 or) zero ????
if (rwNewVal < 0.0) rwNewVal = 0.0;
} else {
int negMirror = mirrorMax - mirror;
while (rwNewVal > mirror || rwNewVal < negMirror) {
//System.out.println("." + " mirror = " + mirror + " newVal = " + newVal);
if (rwNewVal > mirror) rwNewVal = mirror - (rwNewVal - mirror);
if (rwNewVal < negMirror) rwNewVal = negMirror + (negMirror - rwNewVal);
}
// avoid zero ????
if (rwNewVal < 0.0) rwNewVal = 0.0;
}
//System.out.println("Prev = " + prevVal + " stepSize = " + stepSize + " mirror = " + mirror + " newVal = " + newVal);
return rwNewVal;
}
/**
* Specify the number of samples to set the same in
* the low and high noise wave forms.
* The greater the value the less high frequency spectrum
* will be in the LOW and SMOOTH noise types.
*/
public void setNoiseDensity(int newDensity) {
this.noiseDensity = newDensity;
}
/**
* Specify the standard deviation for gaussian noise.
* The dafault for this in 0.25.
*/
public void setStandardDeviation(double newValue) {
this.standardDeviation = newValue;
}
/**
* Specify the mean for gaussian noise.
* The dafault for this in 0.0.
*/
public void setMean(double newValue) {
this.mean = newValue;
}
/**
* Specify the maximum step size for same changes from
* value to value. Value greater than 0.0
*
* @param val The new step size value.
*/
public void setWalkStepSize(double val) {
if (val > 0) walkStepSize = (float) val;
else System.err.println("Walk step size must be greater than zero.");
}
/**
* Specify the maximum value for sample values.
* Controls dynamic range. Values greater than 0.0 only.
*
* @param val The new maximum sample value.
*/
public void setWalkMax(double val) {
if (val > 0) walkMax = (float) val;
else System.err.println("Walk maximum value must be greater than zero.");
}
/**
* Specify the minimum value for sample values.
* Controls dynamic range. Values less than 0.0 only.
*
* @param val The new maximum sample value.
*/
public void setWalkMin(double val) {
if (val < 0) walkMin = (float) val;
else System.err.println("Walk minimum value must be less than zero.");
}
/**
* Specify the maximum number of times the one sample value is repeat - quantise.
* Controls frequency range. Values greater than 0.0 only.
* If the walkVaryDenisty is set to flase, thios value will be absolute, rather than maximum.
*
* @param val The new maximum repeats of each sample value.
*/
public void setWalkNoiseDensity(int val) {
if (val > 0) walkNoiseDensity = val;
else System.err.println("walkNoiseDensity must be greater than zero.");
}
/**
* Will the denisty value vary as a random walk or remain stable?
* Yes if true, variable if false.
*
* @param val The new state, true or false.
*/
public void setWalkVaryDensity(boolean val) {
walkVaryDensity = val;
}
/**
* Specify the minimum number of sample cycles before the Noise Density changes.
* Values greater than 0 only.
*
* @param val The new minium number of sample steps before change.
*/
public void setWalkNoiseDensityMin(int val) {
if (val > 0) walkNoiseDensityMin = val;
else System.err.println("walkNoiseDensityMin must be greater than zero.");
}
/**
* Specify the maximum number of sample cycles before the Noise Density changes.
* Values greater than 0 only.
*
* @param val The new maximum number of sample steps before change.
*/
public void setWalkNoiseDensityMax(int val) {
if (val > 0) walkNoiseDensityMax = val;
else System.err.println("walkNoiseDensityMax must be greater than zero.");
}
/**
* Specify The size of the noise density change at each iteration.
* Values greater than 0 only.
*
* @param val The new maximum value.
*/
public void setWalkNoiseDensityStepSize(int val) {
if (val > 0) walkNoiseDensityStepSize = val;
else System.err.println("walkNoiseDensityMax must be greater than zero.");
}
/**
* Specify the size of the maximum sample time.
* Values between 0 and 100 only.
*
* @param val The new maximum value.
*/
public void setGendynTimeMirror(double newVal) {
if (newVal > 1.0 && newVal <= 100.0) {
this.gendynTimeMirror = (int) newVal;
//System.out.println(newVal);
} else System.err.println("GendynTimeMirror must be between 3 and 100, not " + newVal);
}
/**
* Specify the size of the maximum rand amp value.
* Values between 0 and 100 only.
*
* @param val The new maximum value.
*/
public void setGendynAmpMirror(double newVal) {
if (newVal > 0 && newVal <= 100) {
this.gendynAmpMirror = (int) newVal;
} else System.err.println("GendynAmpMirror must be between 1 and 100, not " + newVal);
}
public double getGendynAmp0() {
return gendynAmp0;
}
public int getGendynPointSize() {
return gendynPointSize;
}
public void setGendynPointSize(int val) {
pointSizeReset = true;
newPointSize = val;
}
private void resetPointSize() {
this.gendynPointSize = newPointSize;
gendynAmpArray = new double[gendynPointSize];
gendynTimeArray = new double[gendynPointSize];
for (int i = 0; i < gendynPointSize; i++) {
gendynAmpArray[i] = 50;
gendynTimeArray[i] = 30;
}
if (getGendynAmpStepSize() < 3) setGendynAmpStepSize(3);
pointSizeReset = false;
}
public double getGendynAmpArray(int i) {
return gendynAmpArray[i];
}
public double getGendynTimeArray(int i) {
return gendynTimeArray[i];
}
public double getGendynAmpStepSize() {
return this.gendynAmpStepSize;
}
public void setGendynAmpStepSize(int val) {
if (val >= 0) this.gendynAmpStepSize = val;
}
public double getGendynTimeStepSize() {
return this.gendynTimeStepSize;
}
public void setGendynTimeStepSize(double val) {
if (val >= 0.0) this.gendynTimeStepSize = val;
}
public void setMaxGendynAmpStepSize(int val) {
if (val >= 0) this.maxGendynAmpStepSize = val;
}
public void setMaxGendynTimeStepSize(int val) {
if (val >= 0) this.maxGendynTimeStepSize = val;
}
public void setGendynPrimaryAmpStepSize(int val) {
if (val >= 0) this.gendynPrimaryAmpStepSize = val;
}
public void setGendynPrimaryTimeStepSize(int val) {
if (val >= 0) this.gendynPrimaryTimeStepSize = val;
}
public void setGendynAmpGranularity(int val) {
this.gendynGranularityUpdate = true;
this.tempGendynGranularity = val;
}
private void updateGranularity() {
if (tempGendynGranularity > 0) this.gendynAmpGranularity = tempGendynGranularity;
}
public void setGendynPrimaryTimeMirror(int val) {
if (val >= 0) this.gendynPrimaryTimeMirror = val;
}
public void setGendynPrimaryAmpMirror(int val) {
if (val >= 0) this.gendynPrimaryAmpMirror = val;
}
public int getGendynInterpolation() {
return this.gendynInterpolation;
}
public void setGendynInterpolation(int val) {
this.gendynInterpolation = val;
//System.out.println("interp set");
}
/**
* Specify the use of linear or gaussian randomness for the Gendyn noise
*
* @param val true = gaussian probability, false = linear probability
*/
public void setGendynGaussian(boolean val) {
this.gendynGaussian = val;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy