/* For Copyright and License see LICENSE.txt and COPYING.txt in the root directory */
package com.nerdscentral.audio.core;
import java.io.File;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
import com.nerdscentral.audio.Messages;
import com.nerdscentral.sython.Caster;
import com.nerdscentral.sython.SFMaths;
import com.nerdscentral.sython.SFPL_RuntimeException;
@SuppressWarnings("nls")
public class SFConstants
{
public static final double SPEED_OF_SOUND = 340.29d;
public static final double THREE_DBS = 3.0102999566398119521373889472449d;
public static double SAMPLE_RATE = 96000.0;
public static double SAMPLE_RATE_MS = 96.0;
public static final double TWELTH_ROOT_TWO = Math.pow(2.0d, 1.0d / 12.0d);
public static final double A4 = 440;
public static final double C4 = 261.625565;
public static final double LINEAR_CENT = 0.0005946d;
public static final double CENT = SFMaths.pow(2.0d, 1.0d / 1200.0d);
private final static HashMap<String, Double> equalNotes = new HashMap<>();
private final static HashMap<String, Double> justNotes = new HashMap<>();
public static final int defaultSplitAt = (int) SAMPLE_RATE;
private static double[] internalDBS = new double[8001];
public final static long ONE_GIG = 1024 * 1024 * 1024;
public static final double UPPER_AUDIBLE_LIMIT = 20000;
public static final double UPPER_ALIAS_LIMIT = 24000;
public static final double NOISE_FLOOR = 1.0 / 32768.00;
public static final int PAGE_SIZE_DOUBLES = 512;
public static final boolean FIND_DEADLOCKS = Boolean
.parseBoolean(System.getProperty("sython.check.deadlocks", "false"));
public static final boolean CHECK_MEMORY = Boolean
.parseBoolean(System.getProperty("sython.check.memory", "false"));
public static boolean TRACE = false;
public static final String RESTART_DIRECTORY = System.getProperty("sython.restart.dir",
System.getProperty("java.io.tmpdir"));
public static final String CACHE_DIRECTORY = System.getProperty("sython.cache.dir",
System.getProperty("java.io.tmpdir"));
static
{
double start = C4 / 16; // C0
// Add sharps and fundamentals
for (int octave = 0; octave < 10; ++octave)
{
for (String rootName : new String[] { "c", "d", "e", "f", "g", "a", "b" })
{
equalNotes.put(rootName + octave, start);
start *= TWELTH_ROOT_TWO;
if (!(rootName.equals("b") || rootName.equals("e"))) //$NON-NLS-2$
{
equalNotes.put(rootName + octave + "#", start); //$NON-NLS-1$
start *= TWELTH_ROOT_TWO;
}
}
}
start = C4 / 16; // C0
// Add flats
for (int octave = 0; octave < 10; ++octave)
{
for (String rootName : new String[] { "c", "d", "e", "f", "g", "a", "b" })
{
// if has a flat add it
if (!(rootName.equals("c") || rootName.equals("f")))
{
equalNotes.put(rootName + octave + "b", start / TWELTH_ROOT_TWO);
}
start *= TWELTH_ROOT_TWO;
if (!(rootName.equals("b") || rootName.equals("e")))
{
start *= TWELTH_ROOT_TWO;
}
}
}
for (double d = -400; d < 400.1; d += 0.1)
{
internalDBS[computeDBSOffset(d)] = slowFromDBs(d);
}
// Just notes
start = C4 / 16; // C0
for (int octave = 0; octave < 10; ++octave)
{
fillInJusts(octave, start);
start *= 2;
}
}
private static void fillInJusts(int rootName, double rootFrequency)
{
justNotes.put("c" + rootName, rootFrequency); //$NON-NLS-1$
justNotes.put("c" + rootName + "#", rootFrequency * 16 / 15); //$NON-NLS-2$
justNotes.put("d" + rootName + "b", rootFrequency * 16 / 15); //$NON-NLS-2$
justNotes.put("d" + rootName, rootFrequency * 9 / 8); //$NON-NLS-1$
justNotes.put("d" + rootName + "#", rootFrequency * 6 / 5); //$NON-NLS-2$
justNotes.put("e" + rootName + "b", rootFrequency * 6 / 5); //$NON-NLS-2$
justNotes.put("e" + rootName, rootFrequency * 5 / 4); //$NON-NLS-1$
justNotes.put("f" + rootName, rootFrequency * 4 / 3); //$NON-NLS-1$
justNotes.put("f" + rootName + "#", rootFrequency * 10 / 7); //$NON-NLS-2$
justNotes.put("g" + rootName + "b", rootFrequency * 10 / 7); //$NON-NLS-2$
justNotes.put("g" + rootName, rootFrequency * 3 / 2); //$NON-NLS-1$
justNotes.put("g" + rootName + "#", rootFrequency * 32 / 21); //$NON-NLS-2$
justNotes.put("a" + rootName + "b", rootFrequency * 32 / 21); //$NON-NLS-2$
justNotes.put("a" + rootName, rootFrequency * 5 / 3); //$NON-NLS-1$
justNotes.put("a" + rootName + "#", rootFrequency * 9 / 5); //$NON-NLS-2$
justNotes.put("b" + rootName + "b", rootFrequency * 9 / 5); //$NON-NLS-2$
justNotes.put("b" + rootName, rootFrequency * 15 / 8); //$NON-NLS-1$
}
public static final double getEqualPitch(String note) throws SFPL_RuntimeException
{
Object ret = equalNotes.get(note.toLowerCase());
if (ret == null)
throw new RuntimeException(Messages.getString("SFConstants.0") + note + Messages.getString("SFConstants.1")); //$NON-NLS-2$
return Caster.makeDouble(ret);
}
/**
* @param to
*/
public static final double closesJustNote(double to)
{
double q = 0;
double d = Double.MAX_VALUE;
for (Double v : equalNotes.values())
{
double m = SFMaths.abs(v - q);
if (m < d)
{
d = m;
q = v;
}
}
return q;
}
@SuppressWarnings("nls")
public static final double getJustPitch(String note) throws SFPL_RuntimeException
{
Object ret = justNotes.get(note.toLowerCase());
if (ret == null)
throw new RuntimeException(Messages.getString("SFConstants.0") + note + Messages.getString("SFConstants.1"));
return Caster.makeDouble(ret);
}
public static double fromDBs(double dbs)
{
int x = computeDBSOffset(dbs);
return x < 0 ? 0 : internalDBS[x];
}
private static int computeDBSOffset(double dbs)
{
return (int) ((dbs + 400) * 10);
}
public static double slowFromDBs(double dbs)
{
return SFMaths.pow(10, dbs / 20.0);
}
public static double slowToDBs(double dbs)
{
return Math.log10(dbs) * 20.0;
}
public static void setSampleRate(double rate)
{
SAMPLE_RATE = rate;
SAMPLE_RATE_MS = rate / 1000.0d;
}
// Directory to send swap files to
private static final String SONIC_FIELD_TEMP = "sython.temp.dirs";
public final static String[] TEMP_DATA_DIRS;
static
{
String tempEnv = System.getProperty(SONIC_FIELD_TEMP);
String[] tdNames = null;
if (tempEnv == null)
{
tdNames = new String[] { System.getProperty("java.io.tmpdir") };
}
else
{
tdNames = tempEnv.split(","); //$NON-NLS-1$
}
TEMP_DATA_DIRS = tdNames;
}
private static class LocalisedTempDir extends ThreadLocal<File>
{
private final AtomicInteger tempRoundRobbin = new AtomicInteger();
@Override
protected File initialValue()
{
int frr = tempRoundRobbin.incrementAndGet() % TEMP_DATA_DIRS.length;
return new File(TEMP_DATA_DIRS[frr]);
}
File getRoundRobbin()
{
return initialValue();
}
}
@SuppressWarnings("synthetic-access")
private static LocalisedTempDir LOCALISE_TEMPDIR = new LocalisedTempDir();
public static File getLocalisedTempDir()
{
return LOCALISE_TEMPDIR.get();
}
public static File getRotatingTempDir()
{
return LOCALISE_TEMPDIR.getRoundRobbin();
}
}