Added audio EQ

This commit is contained in:
2018-09-24 15:47:51 +01:00
parent 36c8cc0a26
commit 2a52f8ccfb
10 changed files with 2013 additions and 54 deletions

View File

@@ -0,0 +1,445 @@
/*
* 21.04.2004 Original verion. davagin@udm.ru.
*-----------------------------------------------------------------------
* 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
* (at your option) 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 davaguine.jeq.core;
import java.io.IOException;
import java.io.InputStream;
/**
* The EqualizerInputStream class
* Author: Dmitry Vaguine
* Date: 02.05.2004
* Time: 12:00:29
*/
public class EqualizerInputStream extends InputStream {
private InputStream stream;
private IIR iir;
private final static int BUFFER_SIZE = 65536;
private byte[] inbuf = new byte[BUFFER_SIZE];
private int[] workbuf = new int[BUFFER_SIZE];
private byte[] outbuf = new byte[BUFFER_SIZE];
private int inpos = 0;
private int inlen = 0;
private int outpos = 0;
private int outlen = 0;
private boolean signed;
private int samplesize;
private boolean bigendian;
/**
* Constructs new EqualizerInputStream object
*
* @param stream is an input stream for pcm data
* @param samplerate is a sample rate of input data
* @param channels is the number of channels
* @param signed indicates that the data is signed
* @param samplesize is the sample bit size of data
* @param bigendian indicates that the dat is in "big endian" encoding
* @param bands is the number of bands
*/
public EqualizerInputStream(InputStream stream, float samplerate, int channels, boolean signed, int samplesize, boolean bigendian, int bands) {
this.stream = stream;
this.iir = new IIR(bands, samplerate, channels);
this.signed = signed;
this.samplesize = samplesize;
this.bigendian = bigendian;
if (!isParamsSupported(samplerate, channels, samplesize, bands))
throw new IllegalArgumentException("Unsupported sample bit size");
}
/**
* Returns Controls of equalizer
*
* @return Controls of equalizer
*/
public IIRControls getControls() {
return iir.getControls();
}
/**
* This is special method for checking of supported parameters of equalizer
*
* @param bands is the number of bands
* @param samplerate is the sample rate of data
* @param channels is the number of channels
* @param samplesize is the size of sample in bits
* @return true if parameters are supported
*/
public static boolean isParamsSupported(float samplerate, int channels, int samplesize, int bands) {
switch (samplesize) {
case 8:
case 16:
case 24:
break;
default:
return false;
}
return IIR.isParamsSupported(bands, samplerate, channels);
}
private boolean fillInBuffer() throws IOException {
if (inpos != 0 && inlen > 0)
System.arraycopy(inbuf, inpos, inbuf, 0, inlen);
inpos = 0;
int num;
boolean eof = false;
while (inlen != inbuf.length) {
num = stream.read(inbuf, inlen, inbuf.length - inlen);
if (num < 0) {
eof = true;
break;
}
inlen += num;
}
return eof;
}
private void fillOutBuffer() {
if (outpos != 0 && outlen > 0)
System.arraycopy(outbuf, outpos, outbuf, 0, outlen);
outpos = 0;
int len = outbuf.length - outlen;
len = inlen < len ? inlen : len;
len = convertToInt(len);
if (len > 0) {
iir.iir(workbuf, len);
len = convertToByte(outbuf, outlen, len);
outlen += len;
}
}
private int convertToInt(int length) {
int l = length;
int temp;
byte a1[];
switch (samplesize) {
case 8: {
if (length > 0) {
System.arraycopy(inbuf, 0, workbuf, 0, length);
inpos += length;
inlen -= length;
}
break;
}
case 16: {
l = length >> 1;
if (l > 0) {
if (bigendian)
for (int i = 0; i < l; i++) {
temp = (((a1 = inbuf)[inpos++] & 0xff) << 8) | (a1[inpos++] & 0xff);
workbuf[i] = signed && temp > 32767 ? temp - 65536 : temp;
}
else
for (int i = 0; i < l; i++) {
temp = ((a1 = inbuf)[inpos++] & 0xff) | ((a1[inpos++] & 0xff) << 8);
workbuf[i] = signed && temp > 32767 ? temp - 65536 : temp;
}
inlen -= inpos;
}
break;
}
case 24: {
l = length / 3;
if (l > 0) {
if (bigendian)
for (int i = 0; i < l; i++) {
temp = ((a1 = inbuf)[inpos++] & 0xff) | ((a1[inpos++] & 0xff) << 8) | ((a1[inpos++] & 0xff) << 16);
workbuf[i] = signed && temp > 8388607 ? temp - 16777216 : temp;
}
else
for (int i = 0; i < l; i++) {
temp = (((a1 = inbuf)[inpos++] & 0xff) << 16) | ((a1[inpos++] & 0xff) << 8) | (a1[inpos++] & 0xff);
workbuf[i] = signed && temp > 8388607 ? temp - 16777216 : temp;
}
inlen -= inpos;
}
break;
}
}
return l;
}
private int wrap8Bit(int data) {
if (data > 127)
data = 127;
else if (data < -128)
data = -128;
if (data < 0)
data += 256;
return data;
}
private int wrap16Bit(int data) {
if (data > 32767)
data = 32767;
else if (data < -32768)
data = -32768;
if (data < 0)
data += 65536;
return data;
}
private int wrap24Bit(int data) {
if (data > 8388607)
data = 8388607;
else if (data < -8388608)
data = -8388608;
if (data < 0)
data += 16777216;
return data;
}
private int convertToByte(byte[] b, int off, int length) {
int p = off;
int d;
switch (samplesize) {
case 8: {
for (int i = 0; i < length; i++)
b[p++] = (byte) (wrap8Bit(workbuf[i]) & 0xff);
break;
}
case 16: {
if (bigendian) {
for (int i = 0; i < length; i++) {
d = wrap16Bit(workbuf[i]);
b[p++] = (byte) ((d & 0xff00) >> 8);
b[p++] = (byte) (d & 0xff);
}
} else {
for (int i = 0; i < length; i++) {
d = wrap16Bit(workbuf[i]);
b[p++] = (byte) (d & 0xff);
b[p++] = (byte) ((d & 0xff00) >> 8);
}
}
break;
}
case 24: {
if (bigendian) {
for (int i = 0; i < length; i++) {
d = wrap24Bit(workbuf[i]);
b[p++] = (byte) (d & 0xff);
b[p++] = (byte) ((d & 0xff00) >> 8);
b[p++] = (byte) ((d & 0xff0000) >> 16);
}
} else {
for (int i = 0; i < length; i++) {
d = wrap24Bit(workbuf[i]);
b[p++] = (byte) ((d & 0xff0000) >> 16);
b[p++] = (byte) ((d & 0xff00) >> 8);
b[p++] = (byte) (d & 0xff);
}
}
break;
}
}
return p - off;
}
/**
* Returns the number of bytes that can be read (or skipped over) from
* this input stream without blocking by the next caller of a method for
* this input stream. The next caller might be the same thread or
* another thread.
*
* @return the number of bytes that can be read from this input stream
* without blocking.
* @throws IOException if an I/O error occurs.
*/
public int available() throws IOException {
return outlen;
}
/**
* Closes this input stream and releases any system resources associated
* with the stream.
*
* @throws IOException if an I/O error occurs.
*/
public void close() throws IOException {
stream.close();
}
/**
* <p> The <code>mark</code> method of <code>EqualizerInputStream</code> does
* nothing.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
*/
public synchronized void mark(int readlimit) {
}
/**
* Tests if this input stream supports the <code>mark</code> and
* <code>reset</code> methods. Whether or not <code>mark</code> and
* <code>reset</code> are supported is an invariant property of a
* particular input stream instance. The <code>markSupported</code> method
* of <code>EqualizerInputStream</code> returns <code>false</code>.
*
* @return false
*/
public boolean markSupported() {
return false;
}
/**
* Reads the next byte of data from the input stream. The value byte is
* returned as an <code>int</code> in the range <code>0</code> to
* <code>255</code>. If no byte is available because the end of the stream
* has been reached, the value <code>-1</code> is returned. This method
* blocks until input data is available, the end of the stream is detected,
* or an exception is thrown.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @throws IOException if an I/O error occurs.
*/
public int read() throws IOException {
if (outlen == 0) {
boolean eof = fillInBuffer();
fillOutBuffer();
if (outlen == 0 && eof)
return -1;
if (outlen == 0 && !eof)
throw new IOException("Impossible state");
}
int b = outbuf[outpos++];
outlen--;
return b;
}
/**
* Reads up to <code>len</code> bytes of data from the input stream into
* an array of bytes. An attempt is made to read as many as
* <code>len</code> bytes, but a smaller number may be read.
* The number of bytes actually read is returned as an integer.
* <p/>
* <p> This method blocks until input data is available, end of file is
* detected, or an exception is thrown.
* <p/>
* <p> If <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
* <p/>
* <p> If <code>off</code> is negative, or <code>len</code> is negative, or
* <code>off+len</code> is greater than the length of the array
* <code>b</code>, then an <code>IndexOutOfBoundsException</code> is
* thrown.
* <p/>
* <p> If <code>len</code> is zero, then no bytes are read and
* <code>0</code> is returned; otherwise, there is an attempt to read at
* least one byte. If no byte is available because the stream is at end of
* file, the value <code>-1</code> is returned; otherwise, at least one
* byte is read and stored into <code>b</code>.
* <p/>
* <p> The first byte read is stored into element <code>b[off]</code>, the
* next one into <code>b[off+1]</code>, and so on. The number of bytes read
* is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
* bytes actually read; these bytes will be stored in elements
* <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
* leaving elements <code>b[off+</code><i>k</i><code>]</code> through
* <code>b[off+len-1]</code> unaffected.
* <p/>
* <p> In every case, elements <code>b[0]</code> through
* <code>b[off]</code> and elements <code>b[off+len]</code> through
* <code>b[b.length-1]</code> are unaffected.
* <p/>
* <p> If the first byte cannot be read for any reason other than end of
* file, then an <code>IOException</code> is thrown. In particular, an
* <code>IOException</code> is thrown if the input stream has been closed.
*
* @param b the buffer into which the data is read.
* @param off the start offset in array <code>b</code>
* at which the data is written.
* @param len the maximum number of bytes to read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @throws IOException if an I/O error occurs.
* @throws NullPointerException if <code>b</code> is <code>null</code>.
*/
public int read(byte[] b, int off, int len) throws IOException {
if (outlen < len) {
boolean eof = fillInBuffer();
fillOutBuffer();
if (outlen == 0 && eof)
return -1;
if (outlen == 0 && !eof)
throw new IOException("Impossible state");
}
len = outlen < len ? outlen : len;
if (len > 0) {
System.arraycopy(outbuf, outpos, b, off, len);
outpos += len;
outlen -= len;
}
return len;
}
/**
* <p>The method <code>reset</code> for class <code>EqualizerInputStream</code>
* does nothing except throw an <code>IOException</code>.
*
* @throws IOException as an indication that the mark feature doesn't supported by EqualizerInputStream.
*/
public void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
/**
* Skips over and discards <code>n</code> bytes of data from this input
* stream. The <code>skip</code> method may, for a variety of reasons, end
* up skipping over some smaller number of bytes, possibly <code>0</code>.
* This may result from any of a number of conditions; reaching end of file
* before <code>n</code> bytes have been skipped is only one possibility.
* The actual number of bytes skipped is returned. If <code>n</code> is
* negative, no bytes are skipped.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
* @throws IOException if an I/O error occurs.
*/
public long skip(long n) throws IOException {
int l;
if (n <= outlen) {
outpos += n;
outlen -= n;
return n;
}
n -= outlen;
l = outlen;
outlen = 0;
outpos = 0;
if (n <= inlen) {
inpos += n;
inlen -= n;
return l + n;
}
n -= inlen;
l += inlen;
inlen = 0;
inpos = 0;
return stream.skip(n) + l;
}
}

View File

@@ -0,0 +1,285 @@
/*
* 21.04.2004 Original verion. davagin@udm.ru.
*-----------------------------------------------------------------------
* 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
* (at your option) 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 davaguine.jeq.core;
/**
* Generic wrapper around IIR algorithm.
* Author: Dmitry Vaguine
* Date: 02.05.2004
* Time: 12:00:29
*/
public class IIR extends IIRBase {
/**
* Max number of channels supported
*/
public final static int EQ_MAX_CHANNELS = 2;
/**
* Max bands supported by the code
*/
public final static int EQ_MAX_BANDS = 31;
/**
* Supported sample rates
*/
public final static float EQ_11025_RATE = 11025;
public final static float EQ_22050_RATE = 22050;
public final static float EQ_44100_RATE = 44100;
public final static float EQ_48000_RATE = 48000;
/**
* Supported number of bands
*/
public final static int EQ_10_BANDS = 10;
public final static int EQ_15_BANDS = 15;
public final static int EQ_25_BANDS = 25;
public final static int EQ_31_BANDS = 31;
/* Indexes for the history arrays
* These have to be kept between calls to this function
* hence they are static */
private int i;
private int j;
private int k;
/* History for two filters */
private XYData[][] dataHistory = new XYData[EQ_MAX_BANDS][EQ_MAX_CHANNELS];
private XYData[][] dataHistory2 = new XYData[EQ_MAX_BANDS][EQ_MAX_CHANNELS];
/* Coefficients */
private IIRCoefficients[] iircf;
/* Equalizer config */
private IIRControls eqcfg;
/* rate */
private float rate;
/* channels */
private int channels;
/* bands */
private int bands;
/**
* Constructs equalizer with given config
*
* @param bands is the number of bands to be used
* @param rate is the sample rate of equalizer
* @param channels is the number of channels
*/
public IIR(int bands, float rate, int channels) {
this.rate = rate;
this.channels = channels;
this.bands = bands;
this.eqcfg = new IIRControls(bands, channels);
if (!isParamsSupported(bands, rate, channels))
throw new IllegalArgumentException("Unsupported parameters");
initIIR();
}
/**
* Returns Controls of equalizer
*
* @return Controls of equalizer
*/
public IIRControls getControls() {
return eqcfg;
}
/**
* This is special method for checking of supported parameters of equalizer
*
* @param bands is the number of bands
* @param rate is the sample rate of data
* @param channels is the number of channels
* @return true if parameters are supported
*/
public static boolean isParamsSupported(int bands, float rate, int channels) {
if (rate != EQ_11025_RATE && rate != EQ_22050_RATE && rate != EQ_44100_RATE && rate != EQ_48000_RATE)
return false;
switch (bands) {
case EQ_10_BANDS:
case EQ_15_BANDS:
case EQ_25_BANDS:
case EQ_31_BANDS:
break;
default:
return false;
}
switch (channels) {
case 1:
case 2:
break;
default:
return false;
}
return (rate != EQ_11025_RATE && rate != EQ_22050_RATE) || bands == EQ_10_BANDS;
}
/* Init the filters */
private void initIIR() {
setFilters();
for (int ii = 0; ii < EQ_MAX_BANDS; ii++)
for (int jj = 0; jj < EQ_MAX_CHANNELS; jj++) {
dataHistory[ii][jj] = new XYData();
dataHistory2[ii][jj] = new XYData();
}
i = 0;
j = 2;
k = 1;
}
private void setFilters() {
if (rate == EQ_11025_RATE)
iircf = iir_cf10_11k_11025;
else if (rate == EQ_22050_RATE)
iircf = iir_cf10_22k_22050;
else if (rate == EQ_44100_RATE) {
switch (bands) {
case 31:
iircf = iir_cf31_44100;
break;
case 25:
iircf = iir_cf25_44100;
break;
case 15:
iircf = iir_cf15_44100;
break;
default:
iircf = iir_cf10_44100;
break;
}
} else if (rate == EQ_48000_RATE) {
switch (bands) {
case 31:
iircf = iir_cf31_48000;
break;
case 25:
iircf = iir_cf25_48000;
break;
case 15:
iircf = iir_cf15_48000;
break;
default:
iircf = iir_cf10_48000;
break;
}
}
}
/**
* Clear filter history.
*/
public void cleanHistory() {
/* Zero the history arrays */
for (int ii = 0; ii < EQ_MAX_BANDS; ii++)
for (int jj = 0; jj < EQ_MAX_CHANNELS; jj++) {
dataHistory[ii][jj].zero();
dataHistory2[ii][jj].zero();
}
i = 0;
j = 2;
k = 1;
}
/**
* Main filtering method.
*
* @param data - data to be filtered
* @param length - length of data in buffer
*/
public void iir(int[] data, int length) {
int index, band, channel;
float eqpreamp[] = eqcfg.getPreamp();
float eqbands[][] = eqcfg.getBands();
double pcm, out;
/**
* IIR filter equation is
* y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2])
*
* NOTE: The 2 factor was introduced in the coefficients to save
* a multiplication
*
* This algorithm cascades two filters to get nice filtering
* at the expense of extra CPU cycles
*/
IIRCoefficients tempcf;
XYData tempd;
for (index = 0; index < length; index += channels) {
/* For each channel */
for (channel = 0; channel < channels; channel++) {
/* Preamp gain */
pcm = data[index + channel] * eqpreamp[channel];
out = 0f;
/* For each band */
for (band = 0; band < bands; band++) {
/* Store Xi(n) */
tempd = dataHistory[band][channel];
tempd.x[i] = pcm;
/* Calculate and store Yi(n) */
tempcf = iircf[band];
tempd.y[i] =
(
/* = alpha * [x(n)-x(n-2)] */
tempcf.alpha * (pcm - tempd.x[k])
/* + gamma * y(n-1) */
+ tempcf.gamma * tempd.y[j]
/* - beta * y(n-2) */
- tempcf.beta * tempd.y[k]
);
/*
* The multiplication by 2.0 was 'moved' into the coefficients to save
* CPU cycles here */
/* Apply the gain */
out += (tempd.y[i] * eqbands[band][channel]); // * 2.0;
} /* For each band */
/* Volume stuff
Scale down original PCM sample and add it to the filters
output. This substitutes the multiplication by 0.25
Go back to use the floating point multiplication before the
conversion to give more dynamic range
*/
out += (pcm * 0.25);
/* Normalize the output */
out *= 4;
/* Round and convert to integer */
data[index + channel] = (int) out;
} /* For each channel */
i++;
j++;
k++;
/* Wrap around the indexes */
if (i == 3)
i = 0;
else if (j == 3)
j = 0;
else
k = 0;
}/* For each pair of samples */
}
}

View File

@@ -0,0 +1,413 @@
/*
* 21.04.2004 Original verion. davagin@udm.ru.
*-----------------------------------------------------------------------
* 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
* (at your option) 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 davaguine.jeq.core;
/**
* Author: Dmitry Vaguine
* Date: 02.05.2004
* Time: 12:00:29
*/
public class IIRBase {
/* BETA, ALPHA, GAMMA */
public final static IIRCoefficients iir_cf10_11k_11025[] = {
/* 31 Hz*/
new IIRCoefficients(9.8758524689e-01, 6.2073765555e-03, 1.9872750693e+00),
/* 62 Hz*/
new IIRCoefficients(9.7532461998e-01, 1.2337690008e-02, 1.9740916593e+00),
/* 125 Hz*/
new IIRCoefficients(9.5087485437e-01, 2.4562572817e-02, 1.9459267562e+00),
/* 250 Hz*/
new IIRCoefficients(9.0416308662e-01, 4.7918456688e-02, 1.8848691023e+00),
/* 500 Hz*/
new IIRCoefficients(8.1751373987e-01, 9.1243130064e-02, 1.7442229115e+00),
/* 1k Hz*/
new IIRCoefficients(6.6840529852e-01, 1.6579735074e-01, 1.4047189863e+00),
/* 2k Hz*/
new IIRCoefficients(4.4858358977e-01, 2.7570820511e-01, 6.0517475334e-01),
/* 3k Hz*/
new IIRCoefficients(3.1012671838e-01, 3.4493664081e-01, -1.8141012760e-01),
/* 4k Hz*/
new IIRCoefficients(2.4198119087e-01, 3.7900940457e-01, -8.0845085113e-01),
/* 5.5k Hz*/
new IIRCoefficients(3.3453245058e-01, 3.3273377471e-01, -1.3344985880e+00)
};
public final static IIRCoefficients iir_cf10_22k_22050[] = {
/* 31 Hz*/
new IIRCoefficients(9.9377323686e-01, 3.1133815717e-03, 1.9936954495e+00),
/* 62 Hz*/
new IIRCoefficients(9.8758524689e-01, 6.2073765555e-03, 1.9872750693e+00),
/* 125 Hz*/
new IIRCoefficients(9.7512812040e-01, 1.2435939802e-02, 1.9738753198e+00),
/* 250 Hz*/
new IIRCoefficients(9.5087485437e-01, 2.4562572817e-02, 1.9459267562e+00),
/* 500 Hz*/
new IIRCoefficients(9.0416308662e-01, 4.7918456688e-02, 1.8848691023e+00),
/* 1k Hz*/
new IIRCoefficients(8.1751373987e-01, 9.1243130064e-02, 1.7442229115e+00),
/* 2k Hz*/
new IIRCoefficients(6.6840529852e-01, 1.6579735074e-01, 1.4047189863e+00),
/* 4k Hz*/
new IIRCoefficients(4.4858358977e-01, 2.7570820511e-01, 6.0517475334e-01),
/* 8k Hz*/
new IIRCoefficients(2.4198119087e-01, 3.7900940457e-01, -8.0845085113e-01),
/* 11k Hz*/
new IIRCoefficients(3.3453245058e-01, 3.3273377471e-01, -1.3344985880e+00)
};
public final static IIRCoefficients iir_cf10_44100[] = {
/* 31 Hz*/
new IIRCoefficients(9.9688176273e-01, 1.5591186337e-03, 1.9968622855e+00),
/* 62 Hz*/
new IIRCoefficients(9.9377323686e-01, 3.1133815717e-03, 1.9936954495e+00),
/* 125 Hz*/
new IIRCoefficients(9.8748575691e-01, 6.2571215431e-03, 1.9871705722e+00),
/* 250 Hz*/
new IIRCoefficients(9.7512812040e-01, 1.2435939802e-02, 1.9738753198e+00),
/* 500 Hz*/
new IIRCoefficients(9.5087485437e-01, 2.4562572817e-02, 1.9459267562e+00),
/* 1k Hz*/
new IIRCoefficients(9.0416308662e-01, 4.7918456688e-02, 1.8848691023e+00),
/* 2k Hz*/
new IIRCoefficients(8.1751373987e-01, 9.1243130064e-02, 1.7442229115e+00),
/* 4k Hz*/
new IIRCoefficients(6.6840529852e-01, 1.6579735074e-01, 1.4047189863e+00),
/* 8k Hz*/
new IIRCoefficients(4.4858358977e-01, 2.7570820511e-01, 6.0517475334e-01),
/* 16k Hz*/
new IIRCoefficients(2.4198119087e-01, 3.7900940457e-01, -8.0845085113e-01)
};
public final static IIRCoefficients iir_cf10_48000[] = {
/* 31 Hz*/
new IIRCoefficients(9.9713475915e-01, 1.4326204244e-03, 1.9971183163e+00),
/* 62 Hz*/
new IIRCoefficients(9.9427771143e-01, 2.8611442874e-03, 1.9942120343e+00),
/* 125 Hz*/
new IIRCoefficients(9.8849666727e-01, 5.7516663664e-03, 1.9882304829e+00),
/* 250 Hz*/
new IIRCoefficients(9.7712566171e-01, 1.1437169144e-02, 1.9760670839e+00),
/* 500 Hz*/
new IIRCoefficients(9.5477456091e-01, 2.2612719547e-02, 1.9505892385e+00),
/* 1k Hz*/
new IIRCoefficients(9.1159452679e-01, 4.4202736607e-02, 1.8952405706e+00),
/* 2k Hz*/
new IIRCoefficients(8.3100647694e-01, 8.4496761532e-02, 1.7686164442e+00),
/* 4k Hz*/
new IIRCoefficients(6.9062328809e-01, 1.5468835596e-01, 1.4641227157e+00),
/* 8k Hz*/
new IIRCoefficients(4.7820368352e-01, 2.6089815824e-01, 7.3910184176e-01),
/* 16k Hz*/
new IIRCoefficients(2.5620076154e-01, 3.7189961923e-01, -6.2810038077e-01)
};
public final static IIRCoefficients iir_cf15_44100[] = {
/* 25 Hz*/
new IIRCoefficients(9.9834072702e-01, 8.2963648917e-04, 1.9983280505e+00),
/* 40 Hz*/
new IIRCoefficients(9.9734652663e-01, 1.3267366865e-03, 1.9973140908e+00),
/* 63 Hz*/
new IIRCoefficients(9.9582396353e-01, 2.0880182333e-03, 1.9957435641e+00),
/* 100 Hz*/
new IIRCoefficients(9.9337951306e-01, 3.3102434709e-03, 1.9931771947e+00),
/* 160 Hz*/
new IIRCoefficients(9.8942832039e-01, 5.2858398053e-03, 1.9889114258e+00),
/* 250 Hz*/
new IIRCoefficients(9.8353109588e-01, 8.2344520610e-03, 1.9822729654e+00),
/* 400 Hz*/
new IIRCoefficients(9.7378088082e-01, 1.3109559588e-02, 1.9705764276e+00),
/* 630 Hz*/
new IIRCoefficients(9.5901979676e-01, 2.0490101620e-02, 1.9511333590e+00),
/* 1k Hz*/
new IIRCoefficients(9.3574903986e-01, 3.2125480071e-02, 1.9161350100e+00),
/* 1.6k Hz*/
new IIRCoefficients(8.9923630641e-01, 5.0381846793e-02, 1.8501014162e+00),
/* 2.5k Hz*/
new IIRCoefficients(8.4722457681e-01, 7.6387711593e-02, 1.7312785699e+00),
/* 4k Hz*/
new IIRCoefficients(7.6755471307e-01, 1.1622264346e-01, 1.4881981417e+00),
/* 6.3k Hz*/
new IIRCoefficients(6.6125377473e-01, 1.6937311263e-01, 1.0357747868e+00),
/* 10k Hz*/
new IIRCoefficients(5.2683267950e-01, 2.3658366025e-01, 2.2218349322e-01),
/* 16k Hz*/
new IIRCoefficients(4.0179628792e-01, 2.9910185604e-01, -9.1248032613e-01)
};
public final static IIRCoefficients iir_cf15_48000[] = {
/* 25 Hz*/
new IIRCoefficients(9.9847546664e-01, 7.6226668143e-04, 1.9984647656e+00),
/* 40 Hz*/
new IIRCoefficients(9.9756184654e-01, 1.2190767289e-03, 1.9975344645e+00),
/* 63 Hz*/
new IIRCoefficients(9.9616261379e-01, 1.9186931041e-03, 1.9960947369e+00),
/* 100 Hz*/
new IIRCoefficients(9.9391578543e-01, 3.0421072865e-03, 1.9937449618e+00),
/* 160 Hz*/
new IIRCoefficients(9.9028307215e-01, 4.8584639242e-03, 1.9898465702e+00),
/* 250 Hz*/
new IIRCoefficients(9.8485897264e-01, 7.5705136795e-03, 1.9837962543e+00),
/* 400 Hz*/
new IIRCoefficients(9.7588512657e-01, 1.2057436715e-02, 1.9731772447e+00),
/* 630 Hz*/
new IIRCoefficients(9.6228521814e-01, 1.8857390928e-02, 1.9556164694e+00),
/* 1k Hz*/
new IIRCoefficients(9.4080933132e-01, 2.9595334338e-02, 1.9242054384e+00),
/* 1.6k Hz*/
new IIRCoefficients(9.0702059196e-01, 4.6489704022e-02, 1.8653476166e+00),
/* 2.5k Hz*/
new IIRCoefficients(8.5868004289e-01, 7.0659978553e-02, 1.7600401337e+00),
/* 4k Hz*/
new IIRCoefficients(7.8409610788e-01, 1.0795194606e-01, 1.5450725522e+00),
/* 6.3k Hz*/
new IIRCoefficients(6.8332861002e-01, 1.5833569499e-01, 1.1426447155e+00),
/* 10k Hz*/
new IIRCoefficients(5.5267518228e-01, 2.2366240886e-01, 4.0186190803e-01),
/* 16k Hz*/
new IIRCoefficients(4.1811888447e-01, 2.9094055777e-01, -7.0905944223e-01)
};
public final static IIRCoefficients iir_cf25_44100[] = {
/* 20 Hz*/
new IIRCoefficients(9.9934037157e-01, 3.2981421662e-04, 1.9993322545e+00),
/* 31.5 Hz*/
new IIRCoefficients(9.9896129025e-01, 5.1935487310e-04, 1.9989411587e+00),
/* 40 Hz*/
new IIRCoefficients(9.9868118265e-01, 6.5940867495e-04, 1.9986487252e+00),
/* 50 Hz*/
new IIRCoefficients(9.9835175161e-01, 8.2412419683e-04, 1.9983010452e+00),
/* 80 Hz*/
new IIRCoefficients(9.9736411067e-01, 1.3179446674e-03, 1.9972343673e+00),
/* 100 Hz*/
new IIRCoefficients(9.9670622662e-01, 1.6468866919e-03, 1.9965035707e+00),
/* 125 Hz*/
new IIRCoefficients(9.9588448566e-01, 2.0577571681e-03, 1.9955679690e+00),
/* 160 Hz*/
new IIRCoefficients(9.9473519326e-01, 2.6324033689e-03, 1.9942169198e+00),
/* 250 Hz*/
new IIRCoefficients(9.9178600786e-01, 4.1069960678e-03, 1.9905226414e+00),
/* 315 Hz*/
new IIRCoefficients(9.8966154150e-01, 5.1692292513e-03, 1.9876580847e+00),
/* 400 Hz*/
new IIRCoefficients(9.8689036168e-01, 6.5548191616e-03, 1.9836646251e+00),
/* 500 Hz*/
new IIRCoefficients(9.8364027156e-01, 8.1798642207e-03, 1.9786090689e+00),
/* 800 Hz*/
new IIRCoefficients(9.7395577681e-01, 1.3022111597e-02, 1.9611472340e+00),
/* 1k Hz*/
new IIRCoefficients(9.6755437936e-01, 1.6222810321e-02, 1.9476180811e+00),
/* 1.25k Hz*/
new IIRCoefficients(9.5961458750e-01, 2.0192706249e-02, 1.9286193446e+00),
/* 1.6k Hz*/
new IIRCoefficients(9.4861481164e-01, 2.5692594182e-02, 1.8982024567e+00),
/* 2.5k Hz*/
new IIRCoefficients(9.2095325455e-01, 3.9523372724e-02, 1.8003794694e+00),
/* 3.15k Hz*/
new IIRCoefficients(9.0153642498e-01, 4.9231787512e-02, 1.7132251201e+00),
/* 4k Hz*/
new IIRCoefficients(8.7685876255e-01, 6.1570618727e-02, 1.5802270232e+00),
/* 5k Hz*/
new IIRCoefficients(8.4886734822e-01, 7.5566325889e-02, 1.3992391376e+00),
/* 8k Hz*/
new IIRCoefficients(7.7175298860e-01, 1.1412350570e-01, 7.4018523020e-01),
/* 10k Hz*/
new IIRCoefficients(7.2627049462e-01, 1.3686475269e-01, 2.5120552756e-01),
/* 12.5k Hz*/
new IIRCoefficients(6.7674787974e-01, 1.6162606013e-01, -3.4978377639e-01),
/* 16k Hz*/
new IIRCoefficients(6.2482197550e-01, 1.8758901225e-01, -1.0576558797e+00),
/* 20k Hz*/
new IIRCoefficients(6.1776148240e-01, 1.9111925880e-01, -1.5492465594e+00)
};
public final static IIRCoefficients iir_cf25_48000[] = {
/* 20 Hz*/
new IIRCoefficients(9.9939388451e-01, 3.0305774630e-04, 1.9993870327e+00),
/* 31.5 Hz*/
new IIRCoefficients(9.9904564663e-01, 4.7717668529e-04, 1.9990286528e+00),
/* 40 Hz*/
new IIRCoefficients(9.9878827195e-01, 6.0586402557e-04, 1.9987608731e+00),
/* 50 Hz*/
new IIRCoefficients(9.9848556942e-01, 7.5721528829e-04, 1.9984427652e+00),
/* 80 Hz*/
new IIRCoefficients(9.9757801538e-01, 1.2109923088e-03, 1.9974684869e+00),
/* 100 Hz*/
new IIRCoefficients(9.9697343933e-01, 1.5132803374e-03, 1.9968023538e+00),
/* 125 Hz*/
new IIRCoefficients(9.9621823598e-01, 1.8908820086e-03, 1.9959510180e+00),
/* 160 Hz*/
new IIRCoefficients(9.9516191728e-01, 2.4190413595e-03, 1.9947243453e+00),
/* 250 Hz*/
new IIRCoefficients(9.9245085008e-01, 3.7745749576e-03, 1.9913840669e+00),
/* 315 Hz*/
new IIRCoefficients(9.9049749914e-01, 4.7512504310e-03, 1.9888056233e+00),
/* 400 Hz*/
new IIRCoefficients(9.8794899744e-01, 6.0255012789e-03, 1.9852245824e+00),
/* 500 Hz*/
new IIRCoefficients(9.8495930023e-01, 7.5203498850e-03, 1.9807093500e+00),
/* 800 Hz*/
new IIRCoefficients(9.7604570090e-01, 1.1977149551e-02, 1.9652207158e+00),
/* 1k Hz*/
new IIRCoefficients(9.7014963927e-01, 1.4925180364e-02, 1.9532947360e+00),
/* 1.25k Hz*/
new IIRCoefficients(9.6283181641e-01, 1.8584091793e-02, 1.9366149237e+00),
/* 1.6k Hz*/
new IIRCoefficients(9.5268463224e-01, 2.3657683878e-02, 1.9100137880e+00),
/* 2.5k Hz*/
new IIRCoefficients(9.2711765003e-01, 3.6441174983e-02, 1.8248457659e+00),
/* 3.15k Hz*/
new IIRCoefficients(9.0912548757e-01, 4.5437256213e-02, 1.7491177803e+00),
/* 4k Hz*/
new IIRCoefficients(8.8619860800e-01, 5.6900696000e-02, 1.6334959111e+00),
/* 5k Hz*/
new IIRCoefficients(8.6010264114e-01, 6.9948679430e-02, 1.4757186436e+00),
/* 8k Hz*/
new IIRCoefficients(7.8757448309e-01, 1.0621275845e-01, 8.9378724155e-01),
/* 10k Hz*/
new IIRCoefficients(7.4415362476e-01, 1.2792318762e-01, 4.5142017567e-01),
/* 12.5k Hz*/
new IIRCoefficients(6.9581428034e-01, 1.5209285983e-01, -1.1091156053e-01),
/* 16k Hz*/
new IIRCoefficients(6.4120506488e-01, 1.7939746756e-01, -8.2060253244e-01),
/* 20k Hz*/
new IIRCoefficients(6.0884213704e-01, 1.9557893148e-01, -1.3932981614e+00)
};
public final static IIRCoefficients iir_cf31_44100[] = {
/* 20 Hz*/
new IIRCoefficients(9.9934037157e-01, 3.2981421662e-04, 1.9993322545e+00),
/* 25 Hz*/
new IIRCoefficients(9.9917555233e-01, 4.1222383516e-04, 1.9991628705e+00),
/* 31.5 Hz*/
new IIRCoefficients(9.9896129025e-01, 5.1935487310e-04, 1.9989411587e+00),
/* 40 Hz*/
new IIRCoefficients(9.9868118265e-01, 6.5940867495e-04, 1.9986487252e+00),
/* 50 Hz*/
new IIRCoefficients(9.9835175161e-01, 8.2412419683e-04, 1.9983010452e+00),
/* 63 Hz*/
new IIRCoefficients(9.9792365217e-01, 1.0381739160e-03, 1.9978431682e+00),
/* 80 Hz*/
new IIRCoefficients(9.9736411067e-01, 1.3179446674e-03, 1.9972343673e+00),
/* 100 Hz*/
new IIRCoefficients(9.9670622662e-01, 1.6468866919e-03, 1.9965035707e+00),
/* 125 Hz*/
new IIRCoefficients(9.9588448566e-01, 2.0577571681e-03, 1.9955679690e+00),
/* 160 Hz*/
new IIRCoefficients(9.9473519326e-01, 2.6324033689e-03, 1.9942169198e+00),
/* 200 Hz*/
new IIRCoefficients(9.9342335280e-01, 3.2883236020e-03, 1.9926141028e+00),
/* 250 Hz*/
new IIRCoefficients(9.9178600786e-01, 4.1069960678e-03, 1.9905226414e+00),
/* 315 Hz*/
new IIRCoefficients(9.8966154150e-01, 5.1692292513e-03, 1.9876580847e+00),
/* 400 Hz*/
new IIRCoefficients(9.8689036168e-01, 6.5548191616e-03, 1.9836646251e+00),
/* 500 Hz*/
new IIRCoefficients(9.8364027156e-01, 8.1798642207e-03, 1.9786090689e+00),
/* 630 Hz*/
new IIRCoefficients(9.7943153305e-01, 1.0284233476e-02, 1.9714629236e+00),
/* 800 Hz*/
new IIRCoefficients(9.7395577681e-01, 1.3022111597e-02, 1.9611472340e+00),
/* 1k Hz*/
new IIRCoefficients(9.6755437936e-01, 1.6222810321e-02, 1.9476180811e+00),
/* 1.25k Hz*/
new IIRCoefficients(9.5961458750e-01, 2.0192706249e-02, 1.9286193446e+00),
/* 1.6k Hz*/
new IIRCoefficients(9.4861481164e-01, 2.5692594182e-02, 1.8982024567e+00),
/* 2k Hz*/
new IIRCoefficients(9.3620971896e-01, 3.1895140519e-02, 1.8581325022e+00),
/* 2.5k Hz*/
new IIRCoefficients(9.2095325455e-01, 3.9523372724e-02, 1.8003794694e+00),
/* 3.15k Hz*/
new IIRCoefficients(9.0153642498e-01, 4.9231787512e-02, 1.7132251201e+00),
/* 4k Hz*/
new IIRCoefficients(8.7685876255e-01, 6.1570618727e-02, 1.5802270232e+00),
/* 5k Hz*/
new IIRCoefficients(8.4886734822e-01, 7.5566325889e-02, 1.3992391376e+00),
/* 6.3k Hz*/
new IIRCoefficients(8.1417575446e-01, 9.2912122771e-02, 1.1311200817e+00),
/* 8k Hz*/
new IIRCoefficients(7.7175298860e-01, 1.1412350570e-01, 7.4018523020e-01),
/* 10k Hz*/
new IIRCoefficients(7.2627049462e-01, 1.3686475269e-01, 2.5120552756e-01),
/* 12.5k Hz*/
new IIRCoefficients(6.7674787974e-01, 1.6162606013e-01, -3.4978377639e-01),
/* 16k Hz*/
new IIRCoefficients(6.2482197550e-01, 1.8758901225e-01, -1.0576558797e+00),
/* 20k Hz*/
new IIRCoefficients(6.1776148240e-01, 1.9111925880e-01, -1.5492465594e+00)
};
public final static IIRCoefficients iir_cf31_48000[] = {
/* 20 Hz*/
new IIRCoefficients(9.9939388451e-01, 3.0305774630e-04, 1.9993870327e+00),
/* 25 Hz*/
new IIRCoefficients(9.9924247917e-01, 3.7876041632e-04, 1.9992317740e+00),
/* 31.5 Hz*/
new IIRCoefficients(9.9904564663e-01, 4.7717668529e-04, 1.9990286528e+00),
/* 40 Hz*/
new IIRCoefficients(9.9878827195e-01, 6.0586402557e-04, 1.9987608731e+00),
/* 50 Hz*/
new IIRCoefficients(9.9848556942e-01, 7.5721528829e-04, 1.9984427652e+00),
/* 63 Hz*/
new IIRCoefficients(9.9809219264e-01, 9.5390367779e-04, 1.9980242502e+00),
/* 80 Hz*/
new IIRCoefficients(9.9757801538e-01, 1.2109923088e-03, 1.9974684869e+00),
/* 100 Hz*/
new IIRCoefficients(9.9697343933e-01, 1.5132803374e-03, 1.9968023538e+00),
/* 125 Hz*/
new IIRCoefficients(9.9621823598e-01, 1.8908820086e-03, 1.9959510180e+00),
/* 160 Hz*/
new IIRCoefficients(9.9516191728e-01, 2.4190413595e-03, 1.9947243453e+00),
/* 200 Hz*/
new IIRCoefficients(9.9395607757e-01, 3.0219612131e-03, 1.9932727986e+00),
/* 250 Hz*/
new IIRCoefficients(9.9245085008e-01, 3.7745749576e-03, 1.9913840669e+00),
/* 315 Hz*/
new IIRCoefficients(9.9049749914e-01, 4.7512504310e-03, 1.9888056233e+00),
/* 400 Hz*/
new IIRCoefficients(9.8794899744e-01, 6.0255012789e-03, 1.9852245824e+00),
/* 500 Hz*/
new IIRCoefficients(9.8495930023e-01, 7.5203498850e-03, 1.9807093500e+00),
/* 630 Hz*/
new IIRCoefficients(9.8108651246e-01, 9.4567437704e-03, 1.9743538683e+00),
/* 800 Hz*/
new IIRCoefficients(9.7604570090e-01, 1.1977149551e-02, 1.9652207158e+00),
/* 1k Hz*/
new IIRCoefficients(9.7014963927e-01, 1.4925180364e-02, 1.9532947360e+00),
/* 1.25k Hz*/
new IIRCoefficients(9.6283181641e-01, 1.8584091793e-02, 1.9366149237e+00),
/* 1.6k Hz*/
new IIRCoefficients(9.5268463224e-01, 2.3657683878e-02, 1.9100137880e+00),
/* 2k Hz*/
new IIRCoefficients(9.4122788957e-01, 2.9386055213e-02, 1.8750821533e+00),
/* 2.5k Hz*/
new IIRCoefficients(9.2711765003e-01, 3.6441174983e-02, 1.8248457659e+00),
/* 3.15k Hz*/
new IIRCoefficients(9.0912548757e-01, 4.5437256213e-02, 1.7491177803e+00),
/* 4k Hz*/
new IIRCoefficients(8.8619860800e-01, 5.6900696000e-02, 1.6334959111e+00),
/* 5k Hz*/
new IIRCoefficients(8.6010264114e-01, 6.9948679430e-02, 1.4757186436e+00),
/* 6.3k Hz*/
new IIRCoefficients(8.2760520925e-01, 8.6197395374e-02, 1.2405797786e+00),
/* 8k Hz*/
new IIRCoefficients(7.8757448309e-01, 1.0621275845e-01, 8.9378724155e-01),
/* 10k Hz*/
new IIRCoefficients(7.4415362476e-01, 1.2792318762e-01, 4.5142017567e-01),
/* 12.5k Hz*/
new IIRCoefficients(6.9581428034e-01, 1.5209285983e-01, -1.1091156053e-01),
/* 16k Hz*/
new IIRCoefficients(6.4120506488e-01, 1.7939746756e-01, -8.2060253244e-01),
/* 20k Hz*/
new IIRCoefficients(6.0884213704e-01, 1.9557893148e-01, -1.3932981614e+00),
};
}

View File

@@ -0,0 +1,36 @@
/*
* 21.04.2004 Original verion. davagin@udm.ru.
*-----------------------------------------------------------------------
* 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
* (at your option) 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 davaguine.jeq.core;
/**
* Author: Dmitry Vaguine
* Date: 02.05.2004
* Time: 12:00:29
*/
public class IIRCoefficients {
public double beta;
public double alpha;
public double gamma;
public IIRCoefficients(double beta, double alpha, double gamma) {
this.beta = beta;
this.alpha = alpha;
this.gamma = gamma;
}
}

View File

@@ -0,0 +1,214 @@
/*
* 21.04.2004 Original verion. davagin@udm.ru.
*-----------------------------------------------------------------------
* 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
* (at your option) 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 davaguine.jeq.core;
/**
* Constols of equalizer
* Author: Dmitry Vaguine
* Date: 02.05.2004
* Time: 12:00:29
*/
public class IIRControls {
/**
* Volume gain
* values should be between 0.0 and 1.0
*/
private float preamp[];
/**
* Gain for each band
* values should be between -0.2 and 1.0
*/
private float bands[][];
/**
* Creates new IIRControls object for given number of bands
*
* @param bandsnum is the number of bands
* @param channels is the number of channels
*/
public IIRControls(int bandsnum, int channels) {
preamp = new float[channels];
bands = new float[bandsnum][channels];
for (int j = 0; j < channels; j++) {
preamp[j] = 1.0f;
for (int i = 0; i < bandsnum; i++)
bands[i][j] = 0f;
}
}
/**
* Returns the maximum value for band control
*
* @return the maximum value for band control
*/
public float getMaximumBandValue() {
return 1.0f;
}
/**
* Returns the minimum value for band control
*
* @return the minimum value for band control
*/
public float getMinimumBandValue() {
return -0.2f;
}
/**
* Returns the maximum value for band control (in Db)
*
* @return the maximum value for band control
*/
public float getMaximumBandDbValue() {
return 12;
}
/**
* Returns the minimum value for band control (in Db)
*
* @return the minimum value for band control
*/
public float getMinimumBandDbValue() {
return -12f;
}
/**
* Returns the maximum value for preamp control
*
* @return the maximum value for preamp control
*/
public float getMaximumPreampValue() {
return 1.0f;
}
/**
* Returns the minimum value for preamp control
*
* @return the minimum value for preamp control
*/
public float getMinimumPreampValue() {
return 0f;
}
/**
* Returns the maximum value for preamp control (in Db)
*
* @return the maximum value for preamp control
*/
public float getMaximumPreampDbValue() {
return 12f;
}
/**
* Returns the minimum value for preamp control (in Db)
*
* @return the minimum value for preamp control
*/
public float getMinimumPreampDbValue() {
return -12f;
}
/**
* Returns bands array
*
* @return bands array
*/
float[][] getBands() {
return bands;
}
/**
* Returns preamp array
*
* @return preamp array
*/
float[] getPreamp() {
return preamp;
}
/**
* Returns value of control for given band and channel
*
* @param band is the index of band
* @param channel is the index of channel
* @return the value
*/
public float getBandValue(int band, int channel) {
return bands[band][channel];
}
/**
* Setter for value of control for given band and channel
*
* @param band is the index of band
* @param channel is the index of channel
* @param value is the new value
*/
public void setBandValue(int band, int channel, float value) {
bands[band][channel] = value;
}
/**
* Setter for value of control for given band and channel (in Db)
*
* @param band is the index of band
* @param channel is the index of channel
* @param value is the new value
*/
public void setBandDbValue(int band, int channel, float value) {
/* Map the gain and preamp values */
/* -12dB .. 12dB mapping */
bands[band][channel] = (float) (2.5220207857061455181125E-01 *
Math.exp(8.0178361802353992349168E-02 * value)
- 2.5220207852836562523180E-01);
}
/**
* Returns value of preamp control for given channel
*
* @param channel is the index of channel
* @return the value
*/
public float getPreampValue(int channel) {
return preamp[channel];
}
/**
* Setter for value of preamp control for given channel
*
* @param channel is the index of channel
* @param value is the new value
*/
public void setPreampValue(int channel, float value) {
preamp[channel] = value;
}
/**
* Setter for value of preamp control for given channel (in Db)
*
* @param channel is the index of channel
* @param value is the new value
*/
public void setPreampDbValue(int channel, float value) {
/* -12dB .. 12dB mapping */
preamp[channel] = (float) (9.9999946497217584440165E-01 *
Math.exp(6.9314738656671842642609E-02 * value)
+ 3.7119444716771825623636E-07);
}
}

View File

@@ -0,0 +1,53 @@
/*
* 21.04.2004 Original verion. davagin@udm.ru.
*-----------------------------------------------------------------------
* 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
* (at your option) 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 davaguine.jeq.core;
/**
* Structure for storing XYData of equalizer.
* Author: Dmitry Vaguine
* Date: 02.05.2004
* Time: 12:00:29
*/
public class XYData {
/**
* X data
*/
public double x[] = new double[3]; /* x[n], x[n-1], x[n-2] */
/**
* Y data
*/
public double y[] = new double[3]; /* y[n], y[n-1], y[n-2] */
/**
* Constructs new XYData object
*/
public XYData() {
zero();
}
/**
* Fills all content with zero
*/
public void zero() {
for (int i = 0; i < 3; i++) {
x[i] = 0;
y[i] = 0;
}
}
}

View File

@@ -0,0 +1,265 @@
/*
* 21.04.2004 Original verion. davagin@udm.ru.
*-----------------------------------------------------------------------
* 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
* (at your option) 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 davaguine.jeq.spi;
import davaguine.jeq.core.IIRControls;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import java.io.IOException;
/**
* The EqualizerInputStream input stream
* Author: Dmitry Vaguine
* Date: 02.05.2004
* Time: 12:00:29
*/
public class EqualizerInputStream extends AudioInputStream {
private davaguine.jeq.core.EqualizerInputStream eq;
/**
* Constructs new audio stream
*
* @param stream input stream with audio data
* @param bands is the number of bands
*/
public EqualizerInputStream(AudioInputStream stream, int bands) {
super(stream, stream.getFormat(), stream.getFrameLength());
AudioFormat format = stream.getFormat();
if (!format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED) && !!format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED))
throw new IllegalArgumentException("Unsupported encoding");
eq = new davaguine.jeq.core.EqualizerInputStream(stream,
format.getSampleRate(),
format.getChannels(),
format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED),
format.getSampleSizeInBits(),
format.isBigEndian(),
bands);
}
/**
* Returns Controls of equalizer
*
* @return Controls of equalizer
*/
public IIRControls getControls() {
return eq.getControls();
}
/**
* This is special method helps to determine supported audio format
*
* @param format is an audio format
* @param bands is the number of bands
* @return true if params supported
*/
public static boolean isParamsSupported(AudioFormat format, int bands) {
if (!format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED) && !!format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED))
return false;
return davaguine.jeq.core.EqualizerInputStream.isParamsSupported(
format.getSampleRate(),
format.getChannels(),
format.getSampleSizeInBits(),
bands);
}
/**
* Returns the number of bytes that can be read (or skipped over) from
* this input stream without blocking by the next caller of a method for
* this input stream. The next caller might be the same thread or
* another thread.
*
* @return the number of bytes that can be read from this input stream
* without blocking.
* @throws java.io.IOException if an I/O error occurs.
*/
public int available() throws IOException {
return eq.available();
}
/**
* Closes this input stream and releases any system resources associated
* with the stream.
*
* @throws IOException if an I/O error occurs.
*/
public void close() throws IOException {
eq.close();
}
/**
* <p> The <code>mark</code> method of <code>EqualizerInputStream</code> does
* nothing.
*
* @param readlimit the maximum limit of bytes that can be read before
* the mark position becomes invalid.
*/
public synchronized void mark(int readlimit) {
eq.mark(readlimit);
}
/**
* Tests if this input stream supports the <code>mark</code> and
* <code>reset</code> methods. Whether or not <code>mark</code> and
* <code>reset</code> are supported is an invariant property of a
* particular input stream instance. The <code>markSupported</code> method
* of <code>EqualizerInputStream</code> returns <code>false</code>.
*
* @return false
*/
public boolean markSupported() {
return eq.markSupported();
}
/**
* Reads the next byte of data from the input stream. The value byte is
* returned as an <code>int</code> in the range <code>0</code> to
* <code>255</code>. If no byte is available because the end of the stream
* has been reached, the value <code>-1</code> is returned. This method
* blocks until input data is available, the end of the stream is detected,
* or an exception is thrown.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* stream is reached.
* @throws IOException if an I/O error occurs.
*/
public int read() throws IOException {
return eq.read();
}
/**
* Reads some number of bytes from the input stream and stores them into
* the buffer array <code>b</code>. The number of bytes actually read is
* returned as an integer. This method blocks until input data is
* available, end of file is detected, or an exception is thrown.
* <p/>
* <p> If <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown. If the length of
* <code>b</code> is zero, then no bytes are read and <code>0</code> is
* returned; otherwise, there is an attempt to read at least one byte. If
* no byte is available because the stream is at end of file, the value
* <code>-1</code> is returned; otherwise, at least one byte is read and
* stored into <code>b</code>.
* <p/>
* <p> The first byte read is stored into element <code>b[0]</code>, the
* next one into <code>b[1]</code>, and so on. The number of bytes read is,
* at most, equal to the length of <code>b</code>. Let <i>k</i> be the
* number of bytes actually read; these bytes will be stored in elements
* <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>,
* leaving elements <code>b[</code><i>k</i><code>]</code> through
* <code>b[b.length-1]</code> unaffected.
* <p/>
* <p> If the first byte cannot be read for any reason other than end of
* file, then an <code>IOException</code> is thrown. In particular, an
* <code>IOException</code> is thrown if the input stream has been closed.
* <p/>
* <p> The <code>read(b)</code> method for class <code>EqualizerInputStream</code>
* has the same effect as: <pre><code> read(b, 0, b.length) </code></pre>
*
* @param b the buffer into which the data is read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> is there is no more data because the end of
* the stream has been reached.
* @throws IOException if an I/O error occurs.
* @throws NullPointerException if <code>b</code> is <code>null</code>.
*/
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
/**
* Reads up to <code>len</code> bytes of data from the input stream into
* an array of bytes. An attempt is made to read as many as
* <code>len</code> bytes, but a smaller number may be read.
* The number of bytes actually read is returned as an integer.
* <p/>
* <p> This method blocks until input data is available, end of file is
* detected, or an exception is thrown.
* <p/>
* <p> If <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
* <p/>
* <p> If <code>off</code> is negative, or <code>len</code> is negative, or
* <code>off+len</code> is greater than the length of the array
* <code>b</code>, then an <code>IndexOutOfBoundsException</code> is
* thrown.
* <p/>
* <p> If <code>len</code> is zero, then no bytes are read and
* <code>0</code> is returned; otherwise, there is an attempt to read at
* least one byte. If no byte is available because the stream is at end of
* file, the value <code>-1</code> is returned; otherwise, at least one
* byte is read and stored into <code>b</code>.
* <p/>
* <p> The first byte read is stored into element <code>b[off]</code>, the
* next one into <code>b[off+1]</code>, and so on. The number of bytes read
* is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
* bytes actually read; these bytes will be stored in elements
* <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
* leaving elements <code>b[off+</code><i>k</i><code>]</code> through
* <code>b[off+len-1]</code> unaffected.
* <p/>
* <p> In every case, elements <code>b[0]</code> through
* <code>b[off]</code> and elements <code>b[off+len]</code> through
* <code>b[b.length-1]</code> are unaffected.
* <p/>
* <p> If the first byte cannot be read for any reason other than end of
* file, then an <code>IOException</code> is thrown. In particular, an
* <code>IOException</code> is thrown if the input stream has been closed.
*
* @param b the buffer into which the data is read.
* @param off the start offset in array <code>b</code>
* at which the data is written.
* @param len the maximum number of bytes to read.
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
* the stream has been reached.
* @throws IOException if an I/O error occurs.
* @throws NullPointerException if <code>b</code> is <code>null</code>.
*/
public int read(byte[] b, int off, int len) throws IOException {
return eq.read(b, off, len);
}
/**
* <p>The method <code>reset</code> for class <code>EqualizerInputStream</code>
* does nothing except throw an <code>IOException</code>.
*
* @throws IOException as an indication that the mark feature doesn't supported by EqualizerInputStream.
*/
public void reset() throws IOException {
eq.reset();
}
/**
* Skips over and discards <code>n</code> bytes of data from this input
* stream. The <code>skip</code> method may, for a variety of reasons, end
* up skipping over some smaller number of bytes, possibly <code>0</code>.
* This may result from any of a number of conditions; reaching end of file
* before <code>n</code> bytes have been skipped is only one possibility.
* The actual number of bytes skipped is returned. If <code>n</code> is
* negative, no bytes are skipped.
*
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
* @throws IOException if an I/O error occurs.
*/
public long skip(long n) throws IOException {
return eq.skip(n);
}
}

View File

@@ -11,6 +11,8 @@ import java.io.*;
public class Options extends JDialog {
JTabbedPane tabs;
GridBagConstraints constraint;
JComboBox<KVPair> mixerList;
@@ -28,10 +30,46 @@ public class Options extends JDialog {
JCheckBox enableParsing;
JSpinner cacheSize;
JSliderOb[] sliders;
JTextFieldOb[] eqvals;
static HashMap<String, String> defaultPrefs;
static Preferences prefs = null;
static class JSliderOb extends JSlider {
Object object;
public JSliderOb(int a, int b, int c) {
super(a, b, c);
}
public void setObject(Object o) {
object = o;
}
public Object getObject() {
return object;
}
}
public class JTextFieldOb extends JTextField {
Object object;
public JTextFieldOb(String s) {
super(s);
}
public void setObject(Object o) {
object = o;
}
public Object getObject() {
return object;
}
}
static class KVPair implements Comparable {
public String key;
public String value;
@@ -66,17 +104,17 @@ public class Options extends JDialog {
}
}
JComboBox<KVPair> addDropdown(String label, KVPair[] options, String def) {
JComboBox<KVPair> addDropdown(JPanel panel, String label, KVPair[] options, String def) {
JLabel l = new JLabel(label);
constraint.gridx = 0;
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.anchor = GridBagConstraints.LINE_START;
add(l, constraint);
panel.add(l, constraint);
JComboBox<KVPair> o = new JComboBox<KVPair>(options);
constraint.gridx = 1;
add(o, constraint);
panel.add(o, constraint);
for (KVPair p : options) {
if (p.key.equals(def)) {
@@ -89,13 +127,13 @@ public class Options extends JDialog {
return o;
}
JTextField addFilePath(String label, String path, boolean dironly) {
JTextField addFilePath(JPanel panel, String label, String path, boolean dironly) {
JLabel l = new JLabel(label);
constraint.gridx = 0;
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.anchor = GridBagConstraints.LINE_START;
add(l, constraint);
panel.add(l, constraint);
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
@@ -149,7 +187,7 @@ public class Options extends JDialog {
constraint.gridx = 1;
constraint.fill = GridBagConstraints.HORIZONTAL;
add(p, constraint);
panel.add(p, constraint);
constraint.fill = GridBagConstraints.NONE;
@@ -157,7 +195,7 @@ public class Options extends JDialog {
return a;
}
void addSeparator() {
void addSeparator(JPanel panel) {
constraint.gridx = 0;
constraint.gridwidth = 2;
@@ -170,20 +208,20 @@ public class Options extends JDialog {
constraint.fill = GridBagConstraints.HORIZONTAL;
constraint.insets = new Insets(10, 2, 10, 2);
add(p, constraint);
panel.add(p, constraint);
constraint.insets = new Insets(2, 2, 2, 2);
constraint.fill = GridBagConstraints.NONE;
constraint.gridwidth = 1;
constraint.gridy++;
}
JSpinner addSpinner(String label, int min, int max, int step, int value, String suffix) {
JSpinner addSpinner(JPanel panel, String label, int min, int max, int step, int value, String suffix) {
JLabel l = new JLabel(label);
constraint.gridx = 0;
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.anchor = GridBagConstraints.LINE_START;
add(l, constraint);
panel.add(l, constraint);
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
@@ -196,7 +234,7 @@ public class Options extends JDialog {
constraint.gridx = 1;
constraint.fill = GridBagConstraints.HORIZONTAL;
add(p, constraint);
panel.add(p, constraint);
constraint.fill = GridBagConstraints.NONE;
@@ -205,11 +243,11 @@ public class Options extends JDialog {
}
JCheckBox addCheckBox(String label, boolean state) {
JCheckBox addCheckBox(JPanel panel, String label, boolean state) {
constraint.gridx = 1;
JCheckBox cb = new JCheckBox(label);
cb.setSelected(state);
add(cb, constraint);
panel.add(cb, constraint);
constraint.gridy++;
return cb;
}
@@ -218,7 +256,13 @@ public class Options extends JDialog {
public Options(JFrame parent) {
loadPreferences(); // Just in case. It should do nothing.
setLayout(new GridBagLayout());
setLayout(new BorderLayout());
tabs = new JTabbedPane();
JPanel optionsPanel = new JPanel();
optionsPanel.setLayout(new GridBagLayout());
constraint = new GridBagConstraints();
@@ -229,41 +273,118 @@ public class Options extends JDialog {
constraint.insets = new Insets(2, 2, 2, 2);
addSeparator();
addSeparator(optionsPanel);
mixerList = addDropdown("Recording device:", getRecordingMixerList(), get("audio.recording.device"));
channelList = addDropdown("Channels:", getChannelCountList(), get("audio.recording.channels"));
rateList = addDropdown("Sample rate:", getSampleRateList(), get("audio.recording.samplerate"));
mixerList = addDropdown(optionsPanel, "Recording device:", getRecordingMixerList(), get("audio.recording.device"));
channelList = addDropdown(optionsPanel, "Channels:", getChannelCountList(), get("audio.recording.channels"));
rateList = addDropdown(optionsPanel, "Sample rate:", getSampleRateList(), get("audio.recording.samplerate"));
addSeparator();
addSeparator(optionsPanel);
playbackList = addDropdown("Playback device:", getPlaybackMixerList(), get("audio.playback.device"));
addSeparator();
storageFolder = addFilePath("Storage folder:", get("path.storage"), true);
playbackList = addDropdown(optionsPanel, "Playback device:", getPlaybackMixerList(), get("audio.playback.device"));
addSeparator(optionsPanel);
storageFolder = addFilePath(optionsPanel, "Storage folder:", get("path.storage"), true);
addSeparator();
addSeparator(optionsPanel);
preChapterGap = addSpinner("Default pre-chapter gap:", 0, 5000, 100, getInteger("catenation.pre-chapter"), "ms");
postChapterGap = addSpinner("Default post-chapter gap:", 0, 5000, 100, getInteger("catenation.post-chapter"), "ms");
postSentenceGap = addSpinner("Default post-sentence gap:", 0, 5000, 100, getInteger("catenation.post-sentence"), "ms");
postParagraphGap = addSpinner("Default post-paragraph gap:", 0, 5000, 100, getInteger("catenation.post-paragraph"), "ms");
preChapterGap = addSpinner(optionsPanel, "Default pre-chapter gap:", 0, 5000, 100, getInteger("catenation.pre-chapter"), "ms");
postChapterGap = addSpinner(optionsPanel, "Default post-chapter gap:", 0, 5000, 100, getInteger("catenation.post-chapter"), "ms");
postSentenceGap = addSpinner(optionsPanel, "Default post-sentence gap:", 0, 5000, 100, getInteger("catenation.post-sentence"), "ms");
postParagraphGap = addSpinner(optionsPanel, "Default post-paragraph gap:", 0, 5000, 100, getInteger("catenation.post-paragraph"), "ms");
addSeparator();
addSeparator(optionsPanel);
ffmpegLocation = addFilePath("FFMPEG location:", get("path.ffmpeg"), false);
bitRate = addDropdown("Export bitrate:", getBitrates(), get("audio.export.bitrate"));
exportRate = addDropdown("Export sample rate:", getSampleRateList(), get("audio.export.samplerate"));
ffmpegLocation = addFilePath(optionsPanel, "FFMPEG location:", get("path.ffmpeg"), false);
bitRate = addDropdown(optionsPanel, "Export bitrate:", getBitrates(), get("audio.export.bitrate"));
exportRate = addDropdown(optionsPanel, "Export sample rate:", getSampleRateList(), get("audio.export.samplerate"));
addSeparator();
addSeparator(optionsPanel);
enableParsing = addCheckBox("Enable automatic sphinx speech-to-text (**SLOW**)", getBoolean("process.sphinx"));
enableParsing = addCheckBox(optionsPanel, "Enable automatic sphinx speech-to-text (**SLOW**)", getBoolean("process.sphinx"));
addSeparator();
addSeparator(optionsPanel);
cacheSize = addSpinner("Cache size:", 0, 5000, 1, getInteger("cache.size"), "");
cacheSize = addSpinner(optionsPanel, "Cache size:", 0, 5000, 1, getInteger("cache.size"), "");
addSeparator();
addSeparator(optionsPanel);
tabs.add("Options", optionsPanel);
JPanel eqPanel = new JPanel();
eqPanel.setLayout(new GridBagLayout());
constraint.gridx = 0;
constraint.gridy = 0;
sliders = new JSliderOb[31];
eqvals = new JTextFieldOb[31];
for (int i = 0; i < 31; i++) {
sliders[i] = new JSliderOb(-120, 120, (int)(Options.getFloat("audio.eq." + i) * 10));
sliders[i].setOrientation(SwingConstants.VERTICAL);
constraint.gridx = i;
constraint.gridy = 0;
eqPanel.add(sliders[i], constraint);
eqvals[i] = new JTextFieldOb(String.format("%.1f", Options.getFloat("audio.eq." + i)));
constraint.gridy = 1;
eqPanel.add(eqvals[i], constraint);
sliders[i].setObject(eqvals[i]);
eqvals[i].setObject(sliders[i]);
eqvals[i].setPreferredSize(new Dimension(40, 20));
sliders[i].addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSliderOb o = (JSliderOb)e.getSource();
String v = String.format("%.1f", (float)o.getValue() / 10.0f);
JTextFieldOb tf = (JTextFieldOb)o.getObject();
tf.setText(v);
}
});
eqvals[i].addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
JTextFieldOb o = (JTextFieldOb)e.getSource();
o.selectAll();
}
public void focusLost(FocusEvent e) {
JTextFieldOb o = (JTextFieldOb)e.getSource();
String v = o.getText();
float f = Utils.s2f(v);
if (f < -12f) f = -12f;
if (f > 12f) f = 12f;
JSliderOb s = (JSliderOb)o.getObject();
s.setValue((int)(f * 10));
o.setText(String.format("%.1f", f));
}
});
eqvals[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JTextFieldOb o = (JTextFieldOb)e.getSource();
String v = o.getText();
float f = Utils.s2f(v);
if (f < -12f) f = -12f;
if (f > 12f) f = 12f;
JSliderOb s = (JSliderOb)o.getObject();
s.setValue((int)(f * 10));
o.setText(String.format("%.1f", f));
o.selectAll();
}
});
}
tabs.add("EQ", eqPanel);
add(tabs, BorderLayout.CENTER);
setTitle("Options");
@@ -297,7 +418,7 @@ public class Options extends JDialog {
constraint.anchor = GridBagConstraints.LINE_END;
add(box, constraint);
add(box, BorderLayout.SOUTH);
pack();
@@ -429,6 +550,38 @@ public class Options extends JDialog {
defaultPrefs.put("cache.size", "100");
defaultPrefs.put("audio.eq.0", "0.00");
defaultPrefs.put("audio.eq.1", "0.00");
defaultPrefs.put("audio.eq.2", "0.00");
defaultPrefs.put("audio.eq.3", "0.00");
defaultPrefs.put("audio.eq.4", "0.00");
defaultPrefs.put("audio.eq.5", "0.00");
defaultPrefs.put("audio.eq.6", "0.00");
defaultPrefs.put("audio.eq.7", "0.00");
defaultPrefs.put("audio.eq.8", "0.00");
defaultPrefs.put("audio.eq.9", "0.00");
defaultPrefs.put("audio.eq.10", "0.00");
defaultPrefs.put("audio.eq.11", "0.00");
defaultPrefs.put("audio.eq.12", "0.00");
defaultPrefs.put("audio.eq.13", "0.00");
defaultPrefs.put("audio.eq.14", "0.00");
defaultPrefs.put("audio.eq.15", "0.00");
defaultPrefs.put("audio.eq.16", "0.00");
defaultPrefs.put("audio.eq.17", "0.00");
defaultPrefs.put("audio.eq.18", "0.00");
defaultPrefs.put("audio.eq.19", "-1.00");
defaultPrefs.put("audio.eq.20", "-2.00");
defaultPrefs.put("audio.eq.21", "-3.00");
defaultPrefs.put("audio.eq.22", "-4.00");
defaultPrefs.put("audio.eq.23", "-5.00");
defaultPrefs.put("audio.eq.24", "-6.00");
defaultPrefs.put("audio.eq.25", "-7.00");
defaultPrefs.put("audio.eq.26", "-8.00");
defaultPrefs.put("audio.eq.27", "-9.00");
defaultPrefs.put("audio.eq.28", "-10.00");
defaultPrefs.put("audio.eq.29", "-11.00");
defaultPrefs.put("audio.eq.30", "-12.00");
if (prefs == null) {
prefs = Preferences.userNodeForPackage(AudiobookRecorder.class);
}
@@ -460,6 +613,15 @@ public class Options extends JDialog {
return 0;
}
public static Float getFloat(String key) {
try {
Float f = Float.parseFloat(get(key));
return f;
} catch (Exception e) {
}
return 0.0f;
}
public static boolean getBoolean(String key) {
String v = get(key);
if (v == null) return false;
@@ -475,6 +637,36 @@ public class Options extends JDialog {
prefs.put(key, value);
}
public static void set(String key, Integer value) {
set(key, String.format("%d", value));
}
public static void set(String key, Boolean value) {
if (value) {
set(key, "true");
} else {
set(key, "false");
}
}
public static void set(String key, Float value) {
set(key, String.format("%.3f", value));
}
public static void set(String key, Object value) {
if (value instanceof Integer) {
set(key, (Integer)value);
} else if (value instanceof Float) {
set(key, (Float)value);
} else if (value instanceof String) {
set(key, (String)value);
} else if (value instanceof Boolean) {
set(key, (Boolean)value);
} else {
System.err.println("Bad type for key " + key);
}
}
void storePreferences() {
set("audio.recording.device", ((KVPair)mixerList.getSelectedItem()).key);
set("audio.recording.channels", ((KVPair)channelList.getSelectedItem()).key);
@@ -482,14 +674,18 @@ public class Options extends JDialog {
set("audio.playback.device", ((KVPair)playbackList.getSelectedItem()).key);
set("path.storage", storageFolder.getText());
set("path.ffmpeg", ffmpegLocation.getText());
set("catenation.pre-chapter", "" + preChapterGap.getValue());
set("catenation.post-chapter", "" + postChapterGap.getValue());
set("catenation.post-sentence", "" + postSentenceGap.getValue());
set("catenation.post-paragraph", "" + postParagraphGap.getValue());
set("catenation.pre-chapter", preChapterGap.getValue());
set("catenation.post-chapter", postChapterGap.getValue());
set("catenation.post-sentence", postSentenceGap.getValue());
set("catenation.post-paragraph", postParagraphGap.getValue());
set("audio.export.bitrate", ((KVPair)bitRate.getSelectedItem()).key);
set("audio.export.samplerate", ((KVPair)exportRate.getSelectedItem()).key);
set("process.sphinx", enableParsing.isSelected() ? "true" : "false");
set("cache.size", "" + cacheSize.getValue());
set("process.sphinx", enableParsing.isSelected());
set("cache.size", cacheSize.getValue());
for (int i = 0; i < 31; i++) {
set("audio.eq." + i, eqvals[i].getText());
}
savePreferences();
}

View File

@@ -12,6 +12,8 @@ import javax.sound.sampled.*;
import edu.cmu.sphinx.api.*;
import edu.cmu.sphinx.decoder.adaptation.*;
import edu.cmu.sphinx.result.*;
import davaguine.jeq.spi.EqualizerInputStream;
import davaguine.jeq.core.IIRControls;
public class Sentence extends DefaultMutableTreeNode implements Cacheable {
@@ -411,16 +413,25 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
// Open the audio file as an AudioInputStream and automatically
// skip the first startOffset frames.
public AudioInputStream getAudioStream() {
public EqualizerInputStream getAudioStream() {
File f = getFile();
try {
AudioInputStream s = AudioSystem.getAudioInputStream(f);
AudioFormat format = s.getFormat();
EqualizerInputStream eq = new EqualizerInputStream(s, 31);
AudioFormat format = eq.getFormat();
IIRControls controls = eq.getControls();
for (int i = 0; i < 31; i++) {
controls.setBandDbValue(i, 0, Options.getFloat("audio.eq." + i));
if (format.getChannels() == 2) {
controls.setBandDbValue(i, 1, Options.getFloat("audio.eq." + i));
}
}
int frameSize = format.getFrameSize();
s.skip(frameSize * startOffset);
eq.skip(frameSize * startOffset);
return s;
return eq;
} catch (Exception e) {
e.printStackTrace();
}
@@ -443,7 +454,18 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
File f = getFile();
try {
AudioInputStream s = AudioSystem.getAudioInputStream(f);
AudioFormat format = s.getFormat();
EqualizerInputStream eq = new EqualizerInputStream(s, 31);
AudioFormat format = eq.getFormat();
IIRControls controls = eq.getControls();
for (int i = 0; i < 31; i++) {
controls.setBandDbValue(i, 0, Options.getFloat("audio.eq." + i));
if (format.getChannels() == 2) {
controls.setBandDbValue(i, 1, Options.getFloat("audio.eq." + i));
}
}
int frameSize = format.getFrameSize();
updateCrossings();
@@ -457,10 +479,10 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
byte[] buffer = new byte[1024];
s.skip(pos);
eq.skip(pos);
while (pos < crossEndOffset * frameSize) {
int nr = s.read(buffer);
int nr = eq.read(buffer);
pos += nr;
play.write(buffer, 0, nr);
@@ -477,15 +499,37 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
try {
updateCrossings();
AudioInputStream s = AudioSystem.getAudioInputStream(f);
AudioFormat format = s.getFormat();
EqualizerInputStream eq = new EqualizerInputStream(s, 31);
AudioFormat format = eq.getFormat();
IIRControls controls = eq.getControls();
for (int i = 0; i < 31; i++) {
controls.setBandDbValue(i, 0, Options.getFloat("audio.eq." + i));
if (format.getChannels() == 2) {
controls.setBandDbValue(i, 1, Options.getFloat("audio.eq." + i));
}
}
int frameSize = format.getFrameSize();
int length = crossEndOffset - crossStartOffset;
byte[] data = new byte[length * frameSize];
s.skip(crossStartOffset * frameSize);
int bytesToRead = length * frameSize;
byte[] data = new byte[bytesToRead];
byte[] buf = new byte[65536];
s.read(data);
int pos = 0;
eq.skip(crossStartOffset * frameSize);
while (bytesToRead > 0) {
int r = eq.read(buf, 0, bytesToRead > 65536 ? 65536 : bytesToRead);
for (int i = 0; i < r; i++) {
data[pos++] = buf[i];
bytesToRead--;
}
}
return data;
} catch (Exception e) {
e.printStackTrace();

View File

@@ -38,4 +38,12 @@ public class Utils {
return 0;
}
public static float s2f(String s) {
try {
return Float.parseFloat(s);
} catch (Exception e) {
}
return 0.0f;
}
}