/* For Copyright and License see LICENSE.txt and COPYING.txt in the root directory */
package com.nerdscentral.audio.amps;
import com.nerdscentral.audio.core.SFData;
import com.nerdscentral.audio.core.SFSignal;
import com.nerdscentral.sython.SFMaths;
import com.nerdscentral.sython.SFPL_RuntimeException;
public class SFAmpAlgorithms
{
public static SFSignal limit(SFSignal in)
{
int len = in.getLength();
SFSignal out = SFData.build(len);
int start = 0;
int end = 0;
for (;;)
{
start = end;
int sign = getSign(in.getSample(end));
double max = 0;
while (end < len && getSign(in.getSample(end)) == sign)
{
double p = SFMaths.abs(in.getSample(end));
if (p > max) max = p;
++end;
}
if (max > 1)
{
max = 1 / max;
}
else
{
max = 1;
}
for (int n = start; n < end; ++n)
{
out.setSample(n, in.getSample(n) * max);
}
if (!(end < len)) break;
}
return out;
}
public static SFSignal maximise(SFSignal in)
{
int len = in.getLength();
SFSignal out = SFData.build(len);
int start = 0;
int end = 0;
for (;;)
{
start = end;
int sign = getSign(in.getSample(end));
double max = 0;
while (end < len && getSign(in.getSample(end)) == sign)
{
double p = SFMaths.abs(in.getSample(end));
if (p > max) max = p;
++end;
}
max = 1 / max;
for (int n = start; n < end; ++n)
{
out.setSample(n, in.getSample(n) * max);
}
if (!(end < len)) break;
}
return out;
}
public static SFSignal makeSquare(SFSignal in)
{
int len = in.getLength();
SFSignal out = SFData.build(len);
int start = 0;
int end = 0;
for (;;)
{
start = end;
int sign = getSign(in.getSample(end));
double sum = 0;
while (end < len && getSign(in.getSample(end)) == sign)
{
sum += SFMaths.abs(in.getSample(end));
++end;
}
// start is the start of the half wave
// end is the end of the half wave
// sum is the area of the half wave
double length = end - start;
double hight = sum / length;
for (int n = start; n < end; ++n)
{
out.setSample(n, sign * hight);
}
if (!(end < len)) break;
}
return out;
}
private static int getSign(double what)
{
return what < 0 ? -1 : 1;
}
public static SFSignal makeTriangle(SFSignal in)
{
int len = in.getLength();
SFSignal out = SFData.build(len);
int start = 0;
int end = 0;
for (;;)
{
start = end;
int sign = getSign(in.getSample(end));
double sum = 0;
while (end < len && getSign(in.getSample(end)) == sign)
{
sum += SFMaths.abs(in.getSample(end));
++end;
}
// start is the start of the half wave
// end is the end of the half wave
// sum is the area of the half wave
double length = end - start;
double hight = sum * 2 / length;
int middle = (int) (start + SFMaths.floor(length / 2));
int middlePoint = middle - start;
if (middlePoint == 0)
{
middlePoint = 1;
}
for (int n = start; n < middle; ++n)
{
out.setSample(n, (sign * hight) * (n - start) / middlePoint);
}
for (int n = middle; n < end; ++n)
{
out.setSample(n, (sign * hight) * (end - n - 1) / middlePoint);
}
if (!(end < len)) break;
}
return out;
}
public static SFSignal makeSawTooth(SFSignal in)
{
int len = in.getLength();
SFSignal out = SFData.build(len);
int start = 0;
int end = 1;
boolean ab = true;
for (;;)
{
// Must use -1 or get an extra zero at the cross over
start = end - 1;
int sign = getSign(in.getSample(end));
double sum = 0;
while (end < len && getSign(in.getSample(end)) == sign)
{
sum += SFMaths.abs(in.getSample(end));
++end;
}
// start is the start of the half wave
// end is the end of the half wave
// sum is the area of the half wave
double length = end - start;
double hight = 2.0d * sum / length;
if (ab)
{
for (int n = start; n < end; ++n)
{
out.setSample(n, (sign * hight) * (end - n - 1) / (end - start));
}
}
else
{
for (int n = start; n < end; ++n)
{
out.setSample(n, (sign * hight) * (n - start) / (end - start));
}
}
ab = !ab;
if (!(end < len)) break;
}
return out;
}
public static SFSignal makeSubOctave(SFSignal in)
{
int len = in.getLength();
SFSignal out = SFData.build(len);
int start = 0;
int end = 0;
int polarity = 1;
int cross = 0;
for (;;)
{
start = end;
double sum = 0;
while (cross++ < 2)
{
int sign = getSign(in.getSample(end));
while (end < len && getSign(in.getSample(end)) == sign)
{
sum += SFMaths.abs(in.getSample(end));
++end;
}
if (!(end < len)) return out;
}
cross = 0;
// start is the start of the wave
// end is the end of the wave
// sum is the area of the wave
double length = end - start;
double hight = sum / (length * 0.65);
final double PI2 = SFMaths.PI * 2.0d;
double f = 0.5 / length;
for (double i = 0; i < length; ++i)
{
out.setSample((int) (i + start), (hight * polarity * SFMaths.sin(i * PI2 * f)));
}
/*
* int middle = (int) (start + SFMaths.floor(length / 2)); int middlePoint = middle - start; if (middlePoint == 0) {
* middlePoint = 1; } for (int n = start; n < middle; ++n) { out.setSample(n, (polarity * hight) * (n - start) /
* middlePoint); } for (int n = middle; n < end; ++n) { out.setSample(n, (polarity * hight) * (end - n - 1) /
* middlePoint); }
*/
if (!(end < len)) break;
polarity = -polarity;
}
return out;
}
public static SFSignal gate(SFSignal in, double threshold)
{
SFSignal ret = in.replicateEmpty();
int length = in.getLength();
for (int index = 0; index < length; ++index)
{
if (in.getSample(index) < threshold)
{
ret.setSample(index, 0);
}
else
{
ret.setSample(index, 1);
}
}
return ret;
}
public static SFSignal threshold(SFSignal in, double threshold)
{
SFSignal ret = in.replicateEmpty();
int length = in.getLength();
for (int index = 0; index < length; ++index)
{
if (in.getSample(index) < threshold)
{
ret.setSample(index, -1);
}
else
{
ret.setSample(index, 1);
}
}
return ret;
}
public static SFSignal shapedThreshold(SFSignal in, SFSignal shape) throws SFPL_RuntimeException
{
SFSignal ret = in.replicateEmpty();
int length = in.getLength();
if (length != shape.getLength()) throw new SFPL_RuntimeException(Messages.getString("SF_AmpAlgorithms.0")); //$NON-NLS-1$
for (int index = 0; index < length; ++index)
{
double threshold = shape.getSample(index);
if (in.getSample(index) < threshold)
{
ret.setSample(index, -1);
}
else
{
ret.setSample(index, 1);
}
}
return ret;
}
}