jm.audio.synth.Waveshaper 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;
/**
* Distorts the input by a specified transfer function.
*
* @author Andrew Brown
*/
public final class Waveshaper extends AudioObject {
/**
* constant for use with shape type
*/
public static final int POLYNOMIAL = 0;
/**
* constant for use with shape type
*/
public static final int CHEBYSHEV = 1;
/**
* Specify shaping function
* 0 = normal polynomial
* 1 = Chebyshev polynomial
*/
private int shapeType = 1;
/**
* The number of polynomials to sum for shaping function
*/
private int stages = 4;
/**
* array of weightings for the polynomial strengths
* values between 0.0 and 1.0 are typical.
*/
private double[] weights;
//----------------------------------------------
// Constructors
//----------------------------------------------
/**
* This constructor takes any AudioObject
* as input and distorts it via the
* default shaping (transfer) function.
*
* @param ao an Audio Object.
*/
public Waveshaper(AudioObject ao) {
super(ao, "[Waveshaper]");
this.shapeType = 1;
this.stages = 4;
double[] defaultWeights = {0.3, 0.8, 0.6, 0.4};
this.weights = defaultWeights;
}
/**
* This constructor takes any AudioObject
* as input and distorts it via a specifed
* shaping (transfer) function to a particular depth.
*
* @param ao an Audio Object.
* @param shape The type of waveshape function to use
* @param depth The number of polynomial stages to use (1-10)
*/
public Waveshaper(AudioObject ao, int shape, int depth) {
super(ao, "[Waveshaper]");
this.shapeType = shape;
this.stages = depth;
double[] defaultWeights = {0.3, 0.8, 0.6, 0.4};
this.weights = defaultWeights;
}
/**
* This constructor takes any AudioObject
* as input and distorts it via a specifed
* shaping (transfer) function to a particular depth.
*
* @param ao an Audio Object.
* @param shape The type of waveshape function to use
* @param depth The number of polynomial stages to use (1-10)
* @param weights An array of volume scaling values for the polynomials
* (make sure the length of the array equals the depth
* minum 1. As the fundamental is assumed to be 1.0)
*/
public Waveshaper(AudioObject ao, int shape, int depth, double[] weights) {
super(ao, "[Waveshaper]");
this.shapeType = shape;
this.stages = depth;
this.weights = weights;
}
//----------------------------------------------
// Methods
//----------------------------------------------
/**
* This nextWork method adds all inputs together
* and passes on a normalised result of the
* sum.
*
* @param input any number of incoming samples
*/
public int work(float[] buffer) throws AOException {
int returned = this.previous[0].nextWork(buffer);
if (shapeType == 0) { // x + x2 + x3 = x4 + x n
for (int i = 0; i < returned; i++) {
float currentValue = Math.abs(buffer[i]);
float result = currentValue;
for (int s = 1; s < stages; s++) {
float product = currentValue;
for (int j = 0; j < s; j++) {
product *= currentValue;
}
result += product * weights[s];
}
if (buffer[i] < 0.0) result *= (float) -1.0;
buffer[i] = result;
}
} else if (shapeType == 1) { // Chebyshev polynomials
for (int i = 0; i < returned; i++) {
float currentValue = Math.abs(buffer[i]);
float result = currentValue;
if (stages > 1) { //T2
result += weights[0] * ((float) 2 * currentValue * currentValue - 1);
}
if (stages > 2) { //T3
result += weights[1] * ((float) 4 * (float) (Math.pow((double) currentValue, 3.0)) -
(float) 3 * currentValue);
}
if (stages > 3) { //T4
result += weights[2] * (8 * (float) (Math.pow((double) currentValue, 4.0)) -
(float) 8 * (float) (Math.pow((double) currentValue, 2.0)) + 1);
}
if (stages > 4) { // T5
result += weights[3] * (16 * (float) (Math.pow((double) currentValue, 5.0)) -
(float) 20.0 * (float) (Math.pow((double) currentValue, 3.0)) +
(float) 5.0 * currentValue);
}
if (stages > 5) { // T6
result += weights[4] * (32 * (float) (Math.pow((double) currentValue, 6.0)) -
(float) 48.0 * (float) (Math.pow((double) currentValue, 4.0)) +
(float) 18.0 * (float) (Math.pow((double) currentValue, 2.0)) - 1);
}
if (stages > 6) { // T7
result += weights[5] * (64 * (float) (Math.pow((double) currentValue, 7.0)) -
(float) 112.0 * (float) (Math.pow((double) currentValue, 5.0)) +
(float) 56.0 * (float) (Math.pow((double) currentValue, 3.0)) -
(float) 7.0 * currentValue);
}
if (stages > 7) { // T8
result += weights[6] * (128 * (float) (Math.pow((double) currentValue, 8.0)) -
(float) 256.0 * (float) (Math.pow((double) currentValue, 6.0)) +
(float) 160.0 * (float) (Math.pow((double) currentValue, 4.0)) -
(float) 32.0 * (float) (Math.pow((double) currentValue, 2.0)) + 1);
}
if (stages > 8) { // T9
result += weights[7] * (256 * (float) (Math.pow((double) currentValue, 9.0)) -
(float) 576.0 * (float) (Math.pow((double) currentValue, 7.0)) +
(float) 432.0 * (float) (Math.pow((double) currentValue, 5.0)) -
(float) 120.0 * (float) (Math.pow((double) currentValue, 3.0)) +
(float) 9.0 * currentValue);
}
if (stages > 9) { // T10
result += weights[8] * (512 * (float) (Math.pow((double) currentValue, 10.0)) -
(float) 1280.0 * (float) (Math.pow((double) currentValue, 8.0)) +
(float) 1120.0 * (float) (Math.pow((double) currentValue, 6.0)) -
(float) 400.0 * (float) (Math.pow((double) currentValue, 4.0)) +
(float) 50.0 * (float) (Math.pow((double) currentValue, 2.0)) - 1);
}
if (buffer[i] < 0.0) result *= (float) -1.0;
buffer[i] = result;
}
}
return returned;
}
}