Compare commits

...

59 Commits

Author SHA1 Message Date
fde4a597c7 Released 0.2.2 2020-01-10 20:23:43 +00:00
e69ae52f50 Updated example filters 2020-01-10 18:55:46 +00:00
8bdb06749f Improvements to LFO 2020-01-10 18:29:22 +00:00
0cfd066f4f Released 0.2.1 2019-12-18 11:31:43 +00:00
217ccb915a Added mono/stereo export option 2019-12-16 15:54:34 +00:00
1dd3e9d86f Add purge backup files menu entry 2019-11-28 14:32:11 +00:00
d3d81d71fe Remove play stop/start 2019-11-28 12:19:31 +00:00
80c110afa9 Added playback block size option 2019-10-13 20:11:07 +01:00
1c08b9a51d Purge cache when changing base effect or reloading effects 2019-09-08 22:37:27 +01:00
4ad30106b6 Move save population to sentence 2019-09-08 22:36:58 +01:00
9100d0e35a Improvements to AGC limiting 2019-09-08 22:36:37 +01:00
b8dea19c30 Make splits continuations and have single playback always 1.00x 2019-09-08 12:30:52 +01:00
671f2b9270 Added adjustable FFT block size 2019-09-07 21:24:46 +01:00
d619fb2f4d Added playback speed option 2019-09-07 20:34:02 +01:00
3eb6704f2f Released 0.2.0 2019-09-05 00:21:04 +01:00
cd24beb8a6 Removed pointless garbage collection calls. Massive speedup 2019-09-05 00:20:29 +01:00
fa287305eb Use 100* integer for gain comparison 2019-09-03 00:12:45 +01:00
3fb656b693 Add small visual gap for paragraphs 2019-09-03 00:12:26 +01:00
f514993525 Added global effects disable and fixed caching problems 2019-09-02 21:44:44 +01:00
81787260c9 Lighten font and make flashing panel alternate red/green 2019-08-27 17:14:17 +01:00
f9ad396228 Added chapter and book level resetting of post gaps 2019-08-25 14:08:25 +01:00
8976f2e359 Add post gap classification 2019-08-25 13:41:46 +01:00
187c3edaf6 Add waveform split and cut functionality 2019-08-14 19:58:06 +01:00
02e85fb354 Released 0.1.9 2019-08-13 14:03:45 +01:00
289834021f Finally fixed pesky memory leak 2019-08-13 14:02:14 +01:00
04fea4acb2 Added race condition debugging and reduced recording buffer size for better responsiveness 2019-08-11 12:51:10 +01:00
54739b0a75 Add Tritex to recording controls 2019-08-11 11:15:55 +01:00
ea5520a729 Fix double apply gain shift in AGC 2019-07-26 14:06:30 +01:00
0a19d8d308 Protect against no effects 2019-07-24 14:17:38 +01:00
4dbe3e23b7 Remove debugging cruft 2019-07-23 12:45:46 +01:00
c43cfc3b69 Improve caching policy 2019-07-23 12:44:24 +01:00
babd3d2052 Release 0.1.8 2019-07-22 23:24:16 +01:00
9464839b4d Turn on JTattoo 2019-07-22 23:24:07 +01:00
bcf7875414 Scrap Sample object and use double[][] instead. Disable processed audio caching - it causes heap overflows 2019-07-22 23:23:03 +01:00
732894a0fb Add Chain effect to connect effects together 2019-07-22 10:43:53 +01:00
146bf5a3c2 Release 0.1.7 2019-07-21 20:03:05 +01:00
b05bfde094 Add pan effect 2019-07-21 20:02:16 +01:00
37d372b8f5 Fix caching of processed audio. Add effect icon and name to tree 2019-07-21 20:02:07 +01:00
c01fee3b73 Switch to Sample object instead of double, and refactor effects for whole sampleset processing 2019-07-21 17:21:50 +01:00
c907e735c6 Prevent stacking of default effect chain 2019-07-21 15:36:33 +01:00
7545e33d2f Make effects two-layerd 2019-07-20 23:03:05 +01:00
ebf961449a Reinstate sphinx to replace defunct Haven 2019-07-18 15:07:04 +01:00
45d6882527 Remove defunct Haven processing 2019-07-18 14:31:59 +01:00
2ec370ad61 Add Shift+Space for Play From 2019-07-18 11:51:07 +01:00
63d5c4af8e Released 0.1.6 2019-07-17 23:14:29 +01:00
9619fd574e Apply default effect to room noise 2019-07-17 23:13:39 +01:00
adeb42070d Added more example filters 2019-07-15 00:50:58 +01:00
d207d246bf Added clipping filter 2019-07-14 22:15:10 +01:00
4dd3a3b874 Released 0.1.5 2019-04-03 13:12:02 +01:00
52b04a754c Added section break and stopped effects chain dropdown from intercepting keypresses 2019-04-03 13:11:19 +01:00
c0efd152e8 Reinstated sample scroll bar 2019-01-21 15:06:30 +00:00
9bda80d40d Update to readme 2019-01-20 13:17:14 +00:00
0e12995063 Added AGC filter 2019-01-20 13:09:52 +00:00
424ebafab5 Detailed LFO in example folder 2019-01-19 16:52:53 +00:00
73d4feb679 Added LFO ring modulator 2019-01-19 16:23:33 +00:00
887b2a9205 Added FFT trim threshold setting and example filters 2019-01-17 00:00:49 +00:00
927eb3e1ff Implemented new effect chain system instead of EQ 2019-01-15 22:43:02 +00:00
fd19f5befe Added Biquad processing class 2019-01-13 23:59:28 +00:00
382775d6ab Reset post sentence gap on record 2019-01-11 22:32:54 +00:00
63 changed files with 3357 additions and 2934 deletions

77
ExampleFilters/README.md Normal file
View File

@@ -0,0 +1,77 @@
Filters are simply XML files with the extension ".eff"
Place them in a folder called `System` within your recordings folder.
The format is:
<effect name="Filter Name">
<filter....>
[optional sub-components or filters]
</filter>
[<filter...>]
</effect>
Currently implemented filters:
<amplifier gain="1.0" />
Amplify (or attenuate) the sample by the given factor (1 = unity gain, 0 = silence, 2 = double, etc)
<lfo frequency="10" depth="0.2" />
Modulate the audio with a low-frequency oscillator. Specify the frequency and a factor of how much to modulate the audio signal. You can also specify an optional `phase="..."` (specified in radians) as an initial phase offset for the modulation.
<biquad type="..." fc="..." q="..." gain="..." />
A Biquad filter of the given type with a center frequency `fc` in Hz, a Q `q` and gain in Decibals of `gain`.
Valid types are:
* lowpass
* highpass
* bandpass
* notch
* peak
* lowshelf
* highshelf
<delay>
<delayline samples="..." gain="...">
[optional effects to apply to the delay line]
</delayline>
</delay>
A multi-tap delay line where each tap can have its own additional filters applied. The delay is given in samples and the gain as
a factor where 1.0 is unity gain.
<group name="Name">
effects in the group
</group>
Allows you to group effects together within a chain. Not of any real use yet (except that the outer wrapper of an effect chain is
actually an effect group) but may be used in the future.
An example: the "Ethereal Voice" - echoes starting off quiet and getting louder with a variable high-pass filter on the pre-echoes. Also
includes a notch filter at 140Hz to cut out a specific annoying hum generated by my computer fans.
<effect name="Ethereal Voice">
<biquad type="notch" fc="140" q="20" gain="-50" />
<amplifier gain="0.1" />
<delayline>
<delay samples="4000" gain="1.0">
<biquad type="highpass" fc="400" q="1" gain="0" />
</delay>
<delay samples="8000" gain="1.5">
<biquad type="highpass" fc="300" q="1" gain="0" />
</delay>
<delay samples="12000" gain="2.0">
<biquad type="highpass" fc="200" q="1" gain="0" />
</delay>
<delay samples="16000" gain="3.0">
<biquad type="highpass" fc="100" q="1" gain="0" />
</delay>
<delay samples="20000" gain="15.0" />
</delayline>
<biquad type="lowshelf" fc="1000" q="2.2" gain="-10" />
<amplifier gain="1.5" />
</effect>

4
ExampleFilters/alien.eff Normal file
View File

@@ -0,0 +1,4 @@
<effect name="Alien">
<!--biquad type="lowpass" fc="10000" q="1" gain="-10" /-->
<lfo frequency="50" depth="1.0" waveform="triangle" mode="replace"/>
</effect>

View File

@@ -0,0 +1,10 @@
<effect name="Big Echo">
<delayline>
<delay samples="22000" gain="0.2" pan="-0.3">
<biquad type="highpass" fc="300" q="1" gain="0" />
</delay>
<delay samples="44000" gain="0.05" pan="0.3">
<biquad type="highpass" fc="600" q="1" gain="0" />
</delay>
</delayline>
</effect>

View File

@@ -0,0 +1,6 @@
<effect name="Cut Computer Hum">
<biquad type="notch" fc="28" q="20" gain="-50" />
<biquad type="notch" fc="91" q="20" gain="-50" />
<biquad type="notch" fc="120" q="20" gain="-50" />
<biquad type="lowpass" fc="10000" q="1" gain="-10" />
</effect>

View File

@@ -0,0 +1,7 @@
<effect name="Cut Computer Hum (with AGC)">
<biquad type="notch" fc="28" q="20" gain="-50" />
<biquad type="notch" fc="91" q="20" gain="-50" />
<biquad type="notch" fc="120" q="20" gain="-50" />
<biquad type="lowpass" fc="10000" q="1" gain="-10" />
<agc ceiling="0.666" limit="1.5" attack="0.08" decay="0.01" />
</effect>

View File

@@ -0,0 +1,15 @@
<effect name="Cut Computer Hum (with AGC and Stereo)">
<biquad type="notch" fc="28" q="20" gain="-50" />
<biquad type="notch" fc="91" q="20" gain="-50" />
<biquad type="notch" fc="120" q="20" gain="-50" />
<biquad type="lowpass" fc="10000" q="1" gain="-10" />
<delayline wetonly="false">
<delay samples="-100" gain="0.1" pan="-1.0">
<biquad type="highpass" fc="300" q="1" gain="0" />
</delay>
<delay samples="100" gain="0.1" pan="1.0">
<biquad type="highpass" fc="300" q="1" gain="0" />
</delay>
</delayline>
<agc ceiling="0.666" limit="1.5" attack="0.1" decay="0.01" />
</effect>

View File

@@ -0,0 +1,20 @@
<effect name="Ethereal Voice">
<amplifier gain="0.1" />
<delayline>
<delay samples="2000" gain="1.0" pan="-0.3">
<biquad type="highpass" fc="400" q="1" gain="0" />
</delay>
<delay samples="4000" gain="1.1" pan="0.3">
<biquad type="highpass" fc="800" q="1" gain="0" />
</delay>
<delay samples="8000" gain="1.2" pan="-0.5">
<biquad type="highpass" fc="1000" q="1" gain="0" />
</delay>
<delay samples="10000" gain="1.3" pan="0.5">
<biquad type="highpass" fc="1500" q="1" gain="0" />
</delay>
<delay samples="12000" gain="15.0" pan="0" />
</delayline>
<biquad type="lowshelf" fc="2000" q="2.2" gain="-10" />
<amplifier gain="1.5" />
</effect>

2
ExampleFilters/flat.eff Normal file
View File

@@ -0,0 +1,2 @@
<effect name="Flat">
</effect>

View File

@@ -0,0 +1,15 @@
<effect name="Large Room (quiet)">
<biquad type="lowpass" fc="10000" q="1" gain="-10" />
<delayline>
<delay samples="5500" gain="0.2" pan="-0.3">
<biquad type="highpass" fc="300" q="1" gain="0" />
</delay>
<delay samples="11000" gain="0.05" pan="0.3">
<biquad type="highpass" fc="600" q="1" gain="0" />
</delay>
<delay samples="16500" gain="0.01" pan="0.0">
<biquad type="highpass" fc="600" q="1" gain="0" />
</delay>
</delayline>
<amplifier gain="0.3" />
</effect>

View File

@@ -0,0 +1,15 @@
<effect name="Large Room (loud)">
<biquad type="lowpass" fc="10000" q="1" gain="-10" />
<delayline>
<delay samples="5500" gain="0.2" pan="-0.3">
<biquad type="highpass" fc="300" q="1" gain="0" />
</delay>
<delay samples="11000" gain="0.05" pan="0.3">
<biquad type="highpass" fc="600" q="1" gain="0" />
</delay>
<delay samples="16500" gain="0.01" pan="0.0">
<biquad type="highpass" fc="600" q="1" gain="0" />
</delay>
</delayline>
<amplifier gain="0.9" />
</effect>

View File

@@ -0,0 +1,3 @@
<effect name="Pan Left">
<pan pan="-0.4" />
</effect>

View File

@@ -0,0 +1,3 @@
<effect name="Pan Right">
<pan pan="0.4" />
</effect>

8
ExampleFilters/phone.eff Normal file
View File

@@ -0,0 +1,8 @@
<effect name="Telephone">
<biquad type="lowshelf" fc="400" q="10" gain="-20" />
<biquad type="highshelf" fc="8000" q="10" gain="-20" />
<delayline>
<delay samples="100" gain="0.5" />
</delayline>
<amplifier gain="1.4" />
</effect>

12
ExampleFilters/radio.eff Normal file
View File

@@ -0,0 +1,12 @@
<effect name="Radio">
<amplifier gain="0.5" />
<biquad type="peak" fc="1000" q="10" gain="25" />
<lfo frequency="3000" depth="0.3" waveform="sine" mode="add" />
<clipping clip="0.9" />
<biquad type="highshelf" fc="8000" q="1" gain="-20" />
<delayline>
<delay samples="100" gain="0.7" />
<delay samples="200" gain="0.5" />
</delayline>
<amplifier gain="0.3" />
</effect>

View File

@@ -0,0 +1,10 @@
<effect name="Robotic">
<biquad type="lowshelf" fc="100" q="2" gain="-20" />
<delayline>
<delay samples="400" gain="1" pan="-0.3" />
<delay samples="800" gain="1" pan="-0.3" />
<delay samples="1200" gain="1" pan="-0.3" />
<delay samples="1600" gain="1" pan="-0.3" />
<delay samples="2000" gain="1" pan="-0.3" />
</delayline>
</effect>

View File

@@ -0,0 +1,10 @@
<effect name="Stereo Chorus">
<delayline>
<delay samples="2000" gain="0.1" pan="-0.3">
<biquad type="highpass" fc="300" q="1" gain="0" />
</delay>
<delay samples="4000" gain="0.1" pan="0.3">
<biquad type="highpass" fc="300" q="1" gain="0" />
</delay>
</delayline>
</effect>

View File

@@ -8,6 +8,7 @@ A system for easing the task of recording and editing audiobooks.
* Zero editing
* MP3 export
* Chapter management
* Audio effect chains (biquad, delay line, etc)
Usage
-----
@@ -52,17 +53,13 @@ edit the text of this ID to identify the recordings. You
may, for instance, change it to have the same text as the
audio contains.
To help with this CMU Sphinx (US EN dictionary) is bundled
with the system and can be used to try and convert the
To help with this the Haven On-Demand online speech recognition
service is integrated with the system and can be used to try and convert the
audio into text. Right clicking on a recording brings
up a menu which includes the option to try and convert
the audio into text. The detected text is then used to
replace the current recording ID / text.
It's far from perfect (especially for a British English
speaker), but it can help you to navigate your way around
a chapter.
File layout
-----------

View File

@@ -25,7 +25,7 @@
debug="true"
debuglevel="lines,vars,source"
encoding="UTF-8"
bootclasspath="${bootclass.path}"
bootclasspath="/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar"
includeAntRuntime="false"
deprecation="true"
srcdir="src"

BIN
deps/sphinx4-core-5prealpha-SNAPSHOT.jar LFS vendored Normal file

Binary file not shown.

BIN
deps/sphinx4-data-5prealpha-SNAPSHOT.jar LFS vendored Normal file

Binary file not shown.

View File

@@ -1 +1 @@
version=0.1.4
version=0.2.2

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

View File

@@ -795,7 +795,7 @@ public abstract class AbstractTheme extends MetalTheme {
public FontUIResource getControlTextFont() {
if (controlFont == null) {
if (JTattooUtilities.isLinux() && JTattooUtilities.isHiresScreen()) {
controlFont = new FontUIResource(DIALOG, Font.BOLD, 14);
controlFont = new FontUIResource(DIALOG, Font.PLAIN, 14); // bold
} else {
controlFont = new FontUIResource(DIALOG, Font.PLAIN, 12);
}
@@ -806,7 +806,7 @@ public abstract class AbstractTheme extends MetalTheme {
public FontUIResource getSystemTextFont() {
if (systemFont == null) {
if (JTattooUtilities.isLinux() && JTattooUtilities.isHiresScreen()) {
systemFont = new FontUIResource(DIALOG, Font.BOLD, 14);
systemFont = new FontUIResource(DIALOG, Font.PLAIN, 14); // bold
} else {
systemFont = new FontUIResource(DIALOG, Font.PLAIN, 12);
}
@@ -817,7 +817,7 @@ public abstract class AbstractTheme extends MetalTheme {
public FontUIResource getUserTextFont() {
if (userFont == null) {
if (JTattooUtilities.isLinux() && JTattooUtilities.isHiresScreen()) {
userFont = new FontUIResource(DIALOG, Font.BOLD, 14);
userFont = new FontUIResource(DIALOG, Font.PLAIN, 14); // bold
} else {
userFont = new FontUIResource(DIALOG, Font.PLAIN, 12);
}
@@ -828,7 +828,7 @@ public abstract class AbstractTheme extends MetalTheme {
public FontUIResource getMenuTextFont() {
if (menuFont == null) {
if (JTattooUtilities.isLinux() && JTattooUtilities.isHiresScreen()) {
menuFont = new FontUIResource(DIALOG, Font.BOLD, 14);
menuFont = new FontUIResource(DIALOG, Font.PLAIN, 14); // bold
} else {
menuFont = new FontUIResource(DIALOG, Font.PLAIN, 12);
}
@@ -839,9 +839,9 @@ public abstract class AbstractTheme extends MetalTheme {
public FontUIResource getWindowTitleFont() {
if (windowTitleFont == null) {
if (JTattooUtilities.isLinux() && JTattooUtilities.isHiresScreen()) {
windowTitleFont = new FontUIResource(DIALOG, Font.BOLD, 14);
windowTitleFont = new FontUIResource(DIALOG, Font.PLAIN, 14); // bold
} else {
windowTitleFont = new FontUIResource(DIALOG, Font.BOLD, 12);
windowTitleFont = new FontUIResource(DIALOG, Font.PLAIN, 12); // bold
}
}
return windowTitleFont;
@@ -850,7 +850,7 @@ public abstract class AbstractTheme extends MetalTheme {
public FontUIResource getSubTextFont() {
if (smallFont == null) {
if (JTattooUtilities.isLinux() && JTattooUtilities.isHiresScreen()) {
smallFont = new FontUIResource(DIALOG, Font.BOLD, 12);
smallFont = new FontUIResource(DIALOG, Font.PLAIN, 12); // bold
} else {
smallFont = new FontUIResource(DIALOG, Font.PLAIN, 10);
}

View File

@@ -125,11 +125,11 @@ public class HiFiDefaultTheme extends AbstractTheme {
tooltipForegroundColor = white;
tooltipBackgroundColor = new ColorUIResource(24, 24, 24);
controlFont = new FontUIResource("Dialog", Font.BOLD, 12);
systemFont = new FontUIResource("Dialog", Font.BOLD, 12);
userFont = new FontUIResource("Dialog", Font.BOLD, 12);
menuFont = new FontUIResource("Dialog", Font.BOLD, 12);
windowTitleFont = new FontUIResource("Dialog", Font.BOLD, 12);
controlFont = new FontUIResource("Dialog", Font.PLAIN, 12); // bold
systemFont = new FontUIResource("Dialog", Font.PLAIN, 12); // bold
userFont = new FontUIResource("Dialog", Font.PLAIN, 12); // bold
menuFont = new FontUIResource("Dialog", Font.PLAIN, 12); // bold
windowTitleFont = new FontUIResource("Dialog", Font.PLAIN, 12); // bold
smallFont = new FontUIResource("Dialog", Font.PLAIN, 10);
}

View File

@@ -42,18 +42,18 @@ public class HiFiLookAndFeel extends AbstractLookAndFeel {
private static final Properties giantFontProps = new Properties();
static {
smallFontProps.setProperty("controlTextFont", "Dialog bold 10");
smallFontProps.setProperty("systemTextFont", "Dialog bold 10");
smallFontProps.setProperty("controlTextFont", "Dialog 10"); // bold
smallFontProps.setProperty("systemTextFont", "Dialog 10"); // bold
smallFontProps.setProperty("userTextFont", "Dialog 10");
smallFontProps.setProperty("menuTextFont", "Dialog bold 10");
smallFontProps.setProperty("windowTitleFont", "Dialog bold 10");
smallFontProps.setProperty("menuTextFont", "Dialog 10"); // bold
smallFontProps.setProperty("windowTitleFont", "Dialog 10"); // bold
smallFontProps.setProperty("subTextFont", "Dialog 8");
largeFontProps.setProperty("controlTextFont", "Dialog bold 14");
largeFontProps.setProperty("systemTextFont", "Dialog bold 14");
largeFontProps.setProperty("userTextFont", "Dialog bold 14");
largeFontProps.setProperty("menuTextFont", "Dialog bold 14");
largeFontProps.setProperty("windowTitleFont", "Dialog bold 14");
largeFontProps.setProperty("controlTextFont", "Dialog 14"); // bold
largeFontProps.setProperty("systemTextFont", "Dialog 14"); // bold
largeFontProps.setProperty("userTextFont", "Dialog 14"); // bold
largeFontProps.setProperty("menuTextFont", "Dialog 14"); // bold
largeFontProps.setProperty("windowTitleFont", "Dialog 14"); // bold
largeFontProps.setProperty("subTextFont", "Dialog 12");
giantFontProps.setProperty("controlTextFont", "Dialog 18");

View File

@@ -1,484 +0,0 @@
/*
* 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:
case 32:
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;
}
case 32: {
l = length / 4;
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) | ((a1[inpos++] & 0xff) << 24);
workbuf[i] = temp; //signed && temp > 8388607 ? temp - 16777216 : temp;
}
else
for (int i = 0; i < l; i++) {
temp = (((a1 = inbuf)[inpos++] & 0xff) << 24) | ((a1[inpos++] & 0xff) << 16) | ((a1[inpos++] & 0xff) << 8) | (a1[inpos++] & 0xff);
workbuf[i] = temp; //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;
}
case 32: {
if (bigendian) {
for (int i = 0; i < length; i++) {
d = workbuf[i];
b[p++] = (byte) (d & 0xff);
b[p++] = (byte) ((d & 0xff00) >> 8);
b[p++] = (byte) ((d & 0xff0000) >> 16);
b[p++] = (byte) ((d & 0xff000000) >> 24);
}
} else {
for (int i = 0; i < length; i++) {
d = wrap24Bit(workbuf[i]);
b[p++] = (byte) ((d & 0xff000000) >> 24);
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

@@ -1,292 +0,0 @@
/*
* 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;
public final static float EQ_96000_RATE = 96000;
/**
* 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 && rate != EQ_96000_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;
}
} else if (rate == EQ_96000_RATE) {
switch (bands) {
case 31:
iircf = iir_cf31_96000;
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

@@ -1,486 +0,0 @@
/*
* 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),
};
public final static IIRCoefficients iir_cf31_96000[] = {
/* 20.0 Hz */
new IIRCoefficients(9.9969659208e-01, 1.517040e-04, 1.9996948789e+00),
/* 25.0 Hz */
new IIRCoefficients(9.9962116126e-01, 1.894194e-04, 1.9996184845e+00),
/* 31.5 Hz */
new IIRCoefficients(9.9952283343e-01, 2.385833e-04, 1.9995185840e+00),
/* 40.0 Hz */
new IIRCoefficients(9.9939398196e-01, 3.030090e-04, 1.9993871301e+00),
/* 50.0 Hz */
new IIRCoefficients(9.9924251688e-01, 3.787416e-04, 1.9992318117e+00),
/* 63.0 Hz */
new IIRCoefficients(9.9904565182e-01, 4.771741e-04, 1.9990286580e+00),
/* 80.0 Hz */
new IIRCoefficients(9.9878828573e-01, 6.058571e-04, 1.9987608868e+00),
/* 100.0 Hz */
new IIRCoefficients(9.9848557077e-01, 7.572146e-04, 1.9984427665e+00),
/* 125.0 Hz */
new IIRCoefficients(9.9810732562e-01, 9.463372e-04, 1.9980404568e+00),
/* 160.0 Hz */
new IIRCoefficients(9.9757801618e-01, 1.210992e-03, 1.9974684877e+00),
/* 200.0 Hz */
new IIRCoefficients(9.9697343858e-01, 1.513281e-03, 1.9968023530e+00),
/* 250.0 Hz */
new IIRCoefficients(9.9621823615e-01, 1.890882e-03, 1.9959510182e+00),
/* 315.0 Hz */
new IIRCoefficients(9.9523733132e-01, 2.381334e-03, 1.9948133101e+00),
/* 400.0 Hz */
new IIRCoefficients(9.9395607744e-01, 3.021961e-03, 1.9932727985e+00),
/* 500.0 Hz */
new IIRCoefficients(9.9245084999e-01, 3.774575e-03, 1.9913840669e+00),
/* 630.0 Hz */
new IIRCoefficients(9.9049749915e-01, 4.751250e-03, 1.9888056234e+00),
/* 800.0 Hz */
new IIRCoefficients(9.8794899744e-01, 6.025501e-03, 1.9852245824e+00),
/* 1000.0 Hz */
new IIRCoefficients(9.8495930024e-01, 7.520350e-03, 1.9807093500e+00),
/* 1250.0 Hz */
new IIRCoefficients(9.8123517675e-01, 9.382412e-03, 1.9746084192e+00),
/* 1600.0 Hz */
new IIRCoefficients(9.7604570090e-01, 1.197715e-02, 1.9652207158e+00),
/* 2000.0 Hz */
new IIRCoefficients(9.7014963927e-01, 1.492518e-02, 1.9532947360e+00),
/* 2500.0 Hz */
new IIRCoefficients(9.6283181641e-01, 1.858409e-02, 1.9366149237e+00),
/* 3150.0 Hz */
new IIRCoefficients(9.5340564248e-01, 2.329718e-02, 1.9120378855e+00),
/* 4000.0 Hz */
new IIRCoefficients(9.4122788957e-01, 2.938606e-02, 1.8750821533e+00),
/* 5000.0 Hz */
new IIRCoefficients(9.2711765003e-01, 3.644117e-02, 1.8248457659e+00),
/* 6300.0 Hz */
new IIRCoefficients(9.0912548757e-01, 4.543726e-02, 1.7491177803e+00),
/* 8000.0 Hz */
new IIRCoefficients(8.8619860800e-01, 5.690070e-02, 1.6334959111e+00),
/* 10000.0 Hz */
new IIRCoefficients(8.6010264114e-01, 6.994868e-02, 1.4757186436e+00),
/* 12500.0 Hz */
new IIRCoefficients(8.2882509035e-01, 8.558745e-02, 1.2501707535e+00),
/* 16000.0 Hz */
new IIRCoefficients(7.8757448309e-01, 1.062128e-01, 8.9378724155e-01),
/* 20000.0 Hz */
new IIRCoefficients(7.4415362476e-01, 1.279232e-01, 4.5142017567e-01),
};
}

View File

@@ -1,36 +0,0 @@
/*
* 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

@@ -1,214 +0,0 @@
/*
* 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

@@ -1,53 +0,0 @@
/*
* 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

@@ -1,265 +0,0 @@
/*
* 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

@@ -0,0 +1,68 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public class AGC implements Effect {
double limit;
double gain;
double ceiling;
double decay;
double attack;
public AGC(double c, double a, double d, double l) {
ceiling = c;
attack = a;
decay = d;
limit = l;
gain = 1d;
}
public String getName() {
return "AGC (Ceiling = " + ceiling + " attack = " + attack + " decay = " + decay + " limit = " + limit;
}
public String toString() {
return getName();
}
public void process(double[][] samples) {
gain = 1d;
for (int i = 0; i < samples.length; i++) {
double absSampleLeft = Math.abs(samples[i][Sentence.LEFT]) * gain;
double absSampleRight = Math.abs(samples[i][Sentence.RIGHT]) * gain;
double factor = 0.0d;
if (absSampleLeft > ceiling) {
factor = -attack;
}
if (absSampleRight > ceiling) {
factor = -attack;
}
if ((absSampleLeft < ceiling) && (absSampleRight < ceiling)) {
factor = decay;
}
gain += factor;
if (gain > limit) gain = limit;
if (gain < 0) gain = 0;
samples[i][Sentence.LEFT] *= gain;
samples[i][Sentence.RIGHT] *= gain;
}
}
public void init(double sr) {
gain = 1d;
}
public void dump() {
System.out.println(toString());
}
public ArrayList<Effect> getChildEffects() {
return null;
}
}

View File

@@ -0,0 +1,47 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public class Amplifier implements Effect {
double gain;
public Amplifier() {
gain = 1.0d;
}
public Amplifier(double g) {
gain = g;
}
public String getName() {
return "Amplifier (" + gain + ")";
}
public ArrayList<Effect> getChildEffects() {
return null;
}
public void process(double[][] samples) {
for (int i = 0; i < samples.length; i++) {
samples[i][Sentence.LEFT] *= gain;
samples[i][Sentence.RIGHT] *= gain;
}
}
public double getGain() {
return gain;
}
public void setGain(double g) {
gain = g;
}
public String toString() {
return getName();
}
public void dump() {
System.out.println(toString());
}
public void init(double sf) {
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,255 @@
package uk.co.majenko.audiobookrecorder;
// Biquad.java
//
// Created by Nigel Redmon on 11/24/12
// EarLevel Engineering: earlevel.com
// Copyright 2012 Nigel Redmon
// Translated to Java 2019 Majenko Technologies
//
// For a complete explanation of the Biquad code:
// http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/
//
// License:
//
// This source code is provided as is, without warranty.
// You may copy and distribute verbatim copies of this document.
// You may modify and use this source code to create binary code
// for your own purposes, free or commercial.
//
import java.util.ArrayList;
public class Biquad implements Effect {
public static final int Lowpass = 0;
public static final int Highpass = 1;
public static final int Bandpass = 2;
public static final int Notch = 3;
public static final int Peak = 4;
public static final int Lowshelf = 5;
public static final int Highshelf = 6;
int type;
double a0, a1, a2, b1, b2;
double Fc, Q, peakGain;
double lz1, lz2;
double rz1, rz2;
double sampleFrequency;
public Biquad() {
type = Lowpass;
a0 = 1.0d;
a1 = 0.0d;
a2 = 0.0d;
b1 = 0.0d;
b2 = 0.0d;
Fc = 440d;
Q = 0.707d;
peakGain = 0.0d;
lz1 = 0.0d;
lz2 = 0.0d;
rz1 = 0.0d;
rz2 = 0.0d;
sampleFrequency = 44100d;
}
public Biquad(int type, double Fc, double Q, double peakGainDB) {
setBiquad(type, Fc, Q, peakGainDB);
lz1 = 0.0;
lz2 = 0.0;
rz1 = 0.0;
rz2 = 0.0;
sampleFrequency = 44100d;
}
public void setType(int typei) {
type = typei;
calcBiquad();
}
public void setQ(double Qi) {
Q = Qi;
calcBiquad();
}
public void setFc(double Fci) {
Fc = Fci;
calcBiquad();
}
public void setPeakGain(double peakGainDB) {
peakGain = peakGainDB;
calcBiquad();
}
public void setBiquad(int typei, double Fci, double Qi, double peakGainDB) {
type = typei;
Q = Qi;
Fc = Fci;
setPeakGain(peakGainDB);
}
public void process(double[][] samples) {
lz1 = 0d;
lz2 = 0d;
rz1 = 0d;
rz2 = 0d;
for (double[] in : samples) {
double lout = in[Sentence.LEFT] * a0 + lz1;
lz1 = in[Sentence.LEFT] * a1 + lz2 - b1 * lout;
lz2 = in[Sentence.LEFT] * a2 - b2 * lout;
double rout = in[Sentence.RIGHT] * a0 + rz1;
rz1 = in[Sentence.RIGHT] * a1 + rz2 - b1 * rout;
rz2 = in[Sentence.RIGHT] * a2 - b2 * rout;
in[Sentence.LEFT] = lout;
in[Sentence.RIGHT] = rout;
}
}
public void init(double sf) {
sampleFrequency = sf;
lz1 = 0d;
lz2 = 0d;
rz1 = 0d;
rz2 = 0d;
calcBiquad();
}
void calcBiquad() {
double norm;
double V = Math.pow(10, Math.abs(peakGain) / 20.0);
double K = Math.tan(Math.PI * (Fc/sampleFrequency));
switch (type) {
case Lowpass:
norm = 1d / (1d + K / Q + K * K);
a0 = K * K * norm;
a1 = 2d * a0;
a2 = a0;
b1 = 2d * (K * K - 1d) * norm;
b2 = (1d - K / Q + K * K) * norm;
break;
case Highpass:
norm = 1d / (1d + K / Q + K * K);
a0 = 1d * norm;
a1 = -2d * a0;
a2 = a0;
b1 = 2d * (K * K - 1d) * norm;
b2 = (1d - K / Q + K * K) * norm;
break;
case Bandpass:
norm = 1d / (1d + K / Q + K * K);
a0 = K / Q * norm;
a1 = 0d;
a2 = -a0;
b1 = 2d * (K * K - 1d) * norm;
b2 = (1d - K / Q + K * K) * norm;
break;
case Notch:
norm = 1d / (1d + K / Q + K * K);
a0 = (1d + K * K) * norm;
a1 = 2d * (K * K - 1d) * norm;
a2 = a0;
b1 = a1;
b2 = (1d - K / Q + K * K) * norm;
break;
case Peak:
if (peakGain >= 0d) { // boost
norm = 1d / (1d + 1d/Q * K + K * K);
a0 = (1d + V/Q * K + K * K) * norm;
a1 = 2d * (K * K - 1d) * norm;
a2 = (1d - V/Q * K + K * K) * norm;
b1 = a1;
b2 = (1d - 1d/Q * K + K * K) * norm;
}
else { // cut
norm = 1d / (1d + V/Q * K + K * K);
a0 = (1d + 1d/Q * K + K * K) * norm;
a1 = 2d * (K * K - 1d) * norm;
a2 = (1d - 1d/Q * K + K * K) * norm;
b1 = a1;
b2 = (1d - V/Q * K + K * K) * norm;
}
break;
case Lowshelf:
if (peakGain >= 0) { // boost
norm = 1d / (1 + Math.sqrt(2d) * K + K * K);
a0 = (1d + Math.sqrt(2d*V) * K + V * K * K) * norm;
a1 = 2d * (V * K * K - 1d) * norm;
a2 = (1d - Math.sqrt(2d*V) * K + V * K * K) * norm;
b1 = 2d * (K * K - 1d) * norm;
b2 = (1d - Math.sqrt(2d) * K + K * K) * norm;
}
else { // cut
norm = 1d / (1 + Math.sqrt(2d*V) * K + V * K * K);
a0 = (1d + Math.sqrt(2d) * K + K * K) * norm;
a1 = 2d * (K * K - 1d) * norm;
a2 = (1d - Math.sqrt(2d) * K + K * K) * norm;
b1 = 2d * (V * K * K - 1d) * norm;
b2 = (1d - Math.sqrt(2d*V) * K + V * K * K) * norm;
}
break;
case Highshelf:
if (peakGain >= 0d) { // boost
norm = 1d / (1d + Math.sqrt(2d) * K + K * K);
a0 = (V + Math.sqrt(2d*V) * K + K * K) * norm;
a1 = 2d * (K * K - V) * norm;
a2 = (V - Math.sqrt(2d*V) * K + K * K) * norm;
b1 = 2d * (K * K - 1d) * norm;
b2 = (1d - Math.sqrt(2d) * K + K * K) * norm;
}
else { // cut
norm = 1d / (V + Math.sqrt(2d*V) * K + K * K);
a0 = (1d + Math.sqrt(2d) * K + K * K) * norm;
a1 = 2d * (K * K - 1d) * norm;
a2 = (1d - Math.sqrt(2d) * K + K * K) * norm;
b1 = 2d * (K * K - V) * norm;
b2 = (V - Math.sqrt(2d*V) * K + K * K) * norm;
}
break;
}
return;
}
public String getName() {
String n = "Biquad Filter (";
switch (type) {
case Lowpass: n += "Lowpass"; break;
case Highpass: n += "Highpass"; break;
case Bandpass: n += "Bandpass"; break;
case Notch: n += "Notch"; break;
case Peak: n += "Peak"; break;
case Lowshelf: n += "Lowshelf"; break;
case Highshelf: n += "Highshelf"; break;
}
n += ", Fc=";
n += Fc;
n += ", Q=";
n += Q;
n += ", Gain=";
n += peakGain;
n += "dB)";
return n;
}
public ArrayList<Effect> getChildEffects() {
return null;
}
public String toString() {
return getName();
}
public void dump() {
System.out.println(toString());
}
}

View File

@@ -8,7 +8,6 @@ import java.util.*;
import java.io.*;
import java.nio.file.*;
import javax.swing.tree.*;
import davaguine.jeq.core.IIRControls;
import javax.sound.sampled.*;
public class Book extends DefaultMutableTreeNode {
@@ -25,10 +24,6 @@ public class Book extends DefaultMutableTreeNode {
ImageIcon icon;
public Equaliser[] equaliser = new Equaliser[2];
float[] eqChannels = new float[31];
Properties prefs;
public Book(Properties p, String bookname) {
@@ -36,8 +31,6 @@ public class Book extends DefaultMutableTreeNode {
prefs = p;
name = bookname;
equaliser[0] = new Equaliser("Default");
equaliser[1] = new Equaliser("Phone");
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name);
}
@@ -187,4 +180,40 @@ public class Book extends DefaultMutableTreeNode {
public void set(String key, Integer value) {
prefs.setProperty(key, "" + value);
}
public File getBookFolder() {
File dir = new File(Options.get("path.storage"), name);
return dir;
}
public ArrayList<String> getUsedEffects() {
ArrayList<String> out = new ArrayList<String>();
for (Enumeration o = children(); o.hasMoreElements();) {
Object ob = (Object)o.nextElement();
if (ob instanceof Chapter) {
Chapter c = (Chapter)ob;
ArrayList<String> effs = c.getUsedEffects();
for (String ef : effs) {
if (out.indexOf(ef) == -1) {
out.add(ef);
}
}
}
}
return out;
}
public void purgeBackups() {
for (Enumeration o = children(); o.hasMoreElements();) {
Object ob = (Object)o.nextElement();
if (ob instanceof Chapter) {
Chapter c = (Chapter)ob;
c.purgeBackups();
}
}
}
}

View File

@@ -3,11 +3,14 @@ package uk.co.majenko.audiobookrecorder;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import javax.swing.border.*;
public class BookTreeRenderer extends DefaultTreeCellRenderer {
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
JLabel ret = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
ret.setIconTextGap(0);
ret.setBorder(new EmptyBorder(0, 0, 0, 0));
if (value instanceof Sentence) {
Sentence s = (Sentence)value;
@@ -31,12 +34,40 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
icn.add(Overlays.important, OverlayIcon.TOP_RIGHT);
}
if (s.getEthereal()) {
icn.add(Overlays.filter, OverlayIcon.BOTTOM_RIGHT);
if (s.getEndOffset() == s.getSampleSize() - 1) {
icn.add(Overlays.important, OverlayIcon.TOP_RIGHT);
}
if (s.getEffectChain() != null) {
if (!s.getEffectChain().equals("none")) {
icn.add(Overlays.filter, OverlayIcon.BOTTOM_RIGHT);
}
}
ret.setIcon(icn);
String gaptype = s.getPostGapType();
DefaultMutableTreeNode prev = s.getPreviousSibling();
String prevtype = "sentence";
if (prev instanceof Sentence) {
Sentence s2 = (Sentence)prev;
prevtype = s2.getPostGapType();
}
if (prevtype.equals("continuation")) {
ret.setIconTextGap(20);
}
if (gaptype.equals("sentence")) {
ret.setBorder(new EmptyBorder(0, 0, 0, 0));
} else if (gaptype.equals("continuation")) {
ret.setBorder(new EmptyBorder(0, 0, 0, 0));
} else if (gaptype.equals("paragraph")) {
ret.setBorder(new EmptyBorder(0, 0, 7, 0));
} else if (gaptype.equals("section")) {
ret.setBorder(new EmptyBorder(0, 0, 15, 0));
}
} else if (value instanceof Chapter) {
ret.setIcon(Icons.chapter);
} else if (value instanceof Book) {

View File

@@ -13,6 +13,9 @@ public class CacheManager {
if (ob.lockedInCache()) {
cache.add(ob);
} else {
if (ob instanceof Sentence) {
Sentence s = (Sentence)ob;
}
ob.clearCache();
}
}
@@ -23,4 +26,19 @@ public class CacheManager {
public static void setCacheSize(int c) {
cacheSize = c;
}
public static void removeFromCache(Cacheable c) {
if (c instanceof Sentence) {
Sentence s = (Sentence)c;
}
cache.remove(c);
c.clearCache();
}
public static void purgeCache() {
for (Cacheable c : cache) {
c.clearCache();
}
cache.clear();
}
}

View File

@@ -0,0 +1,58 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public class Chain implements Effect {
String target;
public Chain(String t) {
target = t;
}
public Chain() {
target = null;
}
public void process(double[][] samples) {
if (target != null) {
Effect t = AudiobookRecorder.window.effects.get(target);
if (t != null) {
t.process(samples);
}
}
}
public void setTarget(String t) {
target = t;
}
public String getTarget() {
return target;
}
public String toString() {
return "Chain to " + target;
}
public void dump() {
System.out.println(toString());
}
public void init(double sf) {
if (target != null) {
Effect t = AudiobookRecorder.window.effects.get(target);
if (t != null) {
t.init(sf);
}
}
}
public ArrayList<Effect> getChildEffects() {
return null;
}
public String getName() {
return toString();
}
}

View File

@@ -116,12 +116,13 @@ public class Chapter extends DefaultMutableTreeNode {
audioAttributes.setCodec("libmp3lame");
audioAttributes.setBitRate(Options.getInteger("audio.export.bitrate"));
audioAttributes.setSamplingRate(Options.getInteger("audio.export.samplerate"));
audioAttributes.setChannels(2); //new Integer(2));
audioAttributes.setChannels(Options.getInteger("audio.export.channels")); //new Integer(2));
attributes.setFormat("mp3");
attributes.setAudioAttributes(audioAttributes);
AudioFormat format = AudiobookRecorder.window.roomNoise.getAudioFormat();
AudioFormat sampleformat = AudiobookRecorder.window.roomNoise.getAudioFormat();
AudioFormat format = new AudioFormat(sampleformat.getSampleRate(), 16, 2, true, false);
byte[] data;
int fullLength = 0;
@@ -149,7 +150,7 @@ public class Chapter extends DefaultMutableTreeNode {
kidno++;
if (exportDialog != null) exportDialog.setProgress(kidno * 1000 / kids);
Sentence snt = (Sentence)s.nextElement();
data = snt.getRawAudioData();
data = snt.getPCMData();
fullLength += data.length;
fos.write(data);
@@ -214,4 +215,38 @@ public class Chapter extends DefaultMutableTreeNode {
return totalTime;
}
public ArrayList<String> getUsedEffects() {
ArrayList<String> out = new ArrayList<String>();
for (Enumeration o = children(); o.hasMoreElements();) {
Object ob = (Object)o.nextElement();
if (ob instanceof Sentence) {
Sentence s = (Sentence)ob;
String ec = s.getEffectChain();
if (out.indexOf(ec) == -1) {
out.add(ec);
}
}
}
return out;
}
public void resetPostGaps() {
for (Enumeration s = children(); s.hasMoreElements();) {
Sentence snt = (Sentence)s.nextElement();
snt.resetPostGap();
}
}
public void purgeBackups() {
for (Enumeration o = children(); o.hasMoreElements();) {
Object ob = (Object)o.nextElement();
if (ob instanceof Sentence) {
Sentence s = (Sentence)ob;
s.purgeBackups();
}
}
}
}

View File

@@ -0,0 +1,49 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public class Clipping implements Effect {
double clip;
public Clipping() {
clip = 1.0d;
}
public Clipping(double g) {
clip = g;
}
public String getName() {
return "Clipping (" + clip + ")";
}
public ArrayList<Effect> getChildEffects() {
return null;
}
public void process(double[][] samples) {
for (double[] sample : samples) {
if (sample[Sentence.LEFT] > clip) sample[Sentence.LEFT] = clip;
if (sample[Sentence.LEFT] < -clip) sample[Sentence.LEFT] = -clip;
if (sample[Sentence.RIGHT] > clip) sample[Sentence.RIGHT] = clip;
if (sample[Sentence.RIGHT] < -clip) sample[Sentence.RIGHT] = -clip;
}
}
public double getClip() {
return clip;
}
public void setClip(double g) {
clip = g;
}
public String toString() {
return getName();
}
public void dump() {
System.out.println(toString());
}
public void init(double sf) {
}
}

View File

@@ -0,0 +1,12 @@
package uk.co.majenko.audiobookrecorder;
public class Debug {
static long timestamp;
static void debug(String msg) {
long now = System.currentTimeMillis();
long diff = now - timestamp;
timestamp = now;
System.err.println(String.format("%8d - %s", diff, msg));
}
}

View File

@@ -0,0 +1,115 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public class DelayLine implements Effect {
ArrayList<DelayLineStore> delayLines;
boolean wetOnly = false;
public DelayLine() {
delayLines = new ArrayList<DelayLineStore>();
}
public String getName() {
return "Delay Line (" + delayLines.size() + " lines)";
}
public void process(double[][] samples) {
double[][] savedSamples = new double[samples.length][2];
for (int i = 0; i < samples.length; i++) {
savedSamples[i][Sentence.LEFT] = samples[i][Sentence.LEFT];
savedSamples[i][Sentence.RIGHT] = samples[i][Sentence.RIGHT];
}
if (wetOnly) {
for (int i = 0; i < samples.length; i++) {
samples[i][Sentence.LEFT] = 0d;
samples[i][Sentence.RIGHT] = 0d;
}
}
double[][] subSamples = new double[samples.length][2];
for (int i = 0; i < samples.length; i++) {
subSamples[i][Sentence.LEFT] = savedSamples[i][Sentence.LEFT];
subSamples[i][Sentence.RIGHT] = savedSamples[i][Sentence.RIGHT];
}
for (DelayLineStore d : delayLines) {
for (int i = 0; i < samples.length; i++) {
subSamples[i][Sentence.LEFT] = savedSamples[i][Sentence.LEFT];
subSamples[i][Sentence.RIGHT] = savedSamples[i][Sentence.RIGHT];
}
d.process(subSamples);
for (int i = 0; i < subSamples.length; i++) {
int off = i + d.getSamples();
if ((off < samples.length) && (off > 0)) {
double[] ns = mix(samples[off], subSamples[i]);
samples[off][Sentence.LEFT] = ns[Sentence.LEFT];
samples[off][Sentence.RIGHT] = ns[Sentence.RIGHT];
}
}
}
}
double[] mix(double[] a, double[] b) {
double[] out = new double[2];
if ((a[Sentence.LEFT] < 0) && (b[Sentence.LEFT] < 0)) {
out[Sentence.LEFT] = (a[Sentence.LEFT] + b[Sentence.LEFT]) - (a[Sentence.LEFT] * b[Sentence.LEFT]);
} else if ((a[Sentence.LEFT] > 0) && (b[Sentence.LEFT] > 0)) {
out[Sentence.LEFT] = (a[Sentence.LEFT] + b[Sentence.LEFT]) - (a[Sentence.LEFT] * b[Sentence.LEFT]);
} else {
out[Sentence.LEFT] = a[Sentence.LEFT] + b[Sentence.LEFT];
}
if ((a[Sentence.RIGHT] < 0) && (b[Sentence.RIGHT] < 0)) {
out[Sentence.RIGHT] = (a[Sentence.RIGHT] + b[Sentence.RIGHT]) - (a[Sentence.RIGHT] * b[Sentence.RIGHT]);
} else if ((a[Sentence.RIGHT] > 0) && (b[Sentence.RIGHT] > 0)) {
out[Sentence.RIGHT] = (a[Sentence.RIGHT] + b[Sentence.RIGHT]) - (a[Sentence.RIGHT] * b[Sentence.RIGHT]);
} else {
out[Sentence.RIGHT] = a[Sentence.RIGHT] + b[Sentence.RIGHT];
}
return out;
}
public DelayLineStore addDelayLine(int samples, double gain, double pan) {
DelayLineStore s = new DelayLineStore(samples, gain, pan);
delayLines.add(s);
return s;
}
public DelayLineStore addDelayLine(int samples, double gain) {
DelayLineStore s = new DelayLineStore(samples, gain);
delayLines.add(s);
return s;
}
public ArrayList<Effect> getChildEffects() {
return null;
}
public String toString() {
return getName();
}
public void dump() {
System.out.println(toString());
for (DelayLineStore s : delayLines) {
s.dump();
}
}
public void init(double sf) {
for (DelayLineStore s : delayLines) {
s.init(sf);
}
}
public void setWetOnly(boolean b) {
wetOnly = b;
}
}

View File

@@ -0,0 +1,78 @@
package uk.co.majenko.audiobookrecorder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.ArrayList;
public class DelayLineStore {
double gain;
int numSamples;
double pan;
ArrayList<Effect> effects;
public DelayLineStore(int s, double g, double p) {
numSamples = s;
gain = g;
pan = p;
effects = new ArrayList<Effect>();
}
public DelayLineStore(int s, double g) {
numSamples = s;
gain = g;
pan = 0d;
effects = new ArrayList<Effect>();
}
public void process(double[][] samples) {
for (Effect e : effects) {
e.process(samples);
}
for (double[] sample : samples) {
sample[Sentence.LEFT] *= gain;
sample[Sentence.RIGHT] *= gain;
if (pan < 0) {
double p = 1 + pan;
sample[Sentence.RIGHT] *= p;
} else {
double p = 1 - pan;
sample[Sentence.LEFT] *= p;
}
}
}
public void setSamples(int s) {
numSamples = s;
}
public void setGain(double g) {
gain = g;
}
public int getSamples() {
return numSamples;
}
public double getGain() {
return gain;
}
public void addEffect(Effect e) {
effects.add(e);
}
public void init(double sf) {
for (Effect e : effects) {
e.init(sf);
}
}
public void dump() {
System.out.println(" Samples: " + numSamples + ", gain: " + gain);
for (Effect e : effects) {
e.dump();
}
}
}

View File

@@ -0,0 +1,12 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public interface Effect {
public void process(double[][] samples);
public String getName();
public ArrayList<Effect> getChildEffects();
public void dump();
public void init(double sr);
public String toString();
}

View File

@@ -0,0 +1,69 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public class EffectGroup implements Effect {
String name;
ArrayList<Effect> effects;
public EffectGroup(String n) {
name = n;
effects = new ArrayList<Effect>();
}
public EffectGroup() {
name = "Unnamed Group";
effects = new ArrayList<Effect>();
}
public void process(double[][] samples) {
for (Effect e : effects) {
e.process(samples);
}
}
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void addEffect(Effect e) {
effects.add(e);
}
public void clearEffects() {
effects.clear();
}
public void removeEffect(Effect e) {
effects.remove(e);
}
public void removeEffect(int n) {
effects.remove(n);
}
public ArrayList<Effect> getChildEffects() {
return effects;
}
public String toString() {
return name;
}
public void dump() {
System.out.println(toString() + " >> ");
for (Effect e : effects) {
e.dump();
}
}
public void init(double sf) {
for (Effect e : effects) {
e.init(sf);
}
}
}

View File

@@ -1,106 +0,0 @@
package uk.co.majenko.audiobookrecorder;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.nio.file.*;
import javax.swing.tree.*;
import javax.sound.sampled.*;
import davaguine.jeq.core.IIRControls;
public class Equaliser extends JPanel {
EqualiserChannel channels[];
String name;
static final double[] frequencies = {
20d, 25d, 31.5d, 40d, 50d, 63d, 80d, 100d, 125d, 160d, 200d,
250d, 315d, 400d, 500d, 630d, 800d, 1000d, 1250d, 1600d, 2000d,
2500d, 3150d, 4000d, 5000d, 6300d, 8000d, 10000d, 12500d, 16000d,
20000d
};
public Equaliser(String n) {
super();
name = n;
channels = new EqualiserChannel[31];
setLayout(new BorderLayout());
JPanel inner = new JPanel();
inner.setLayout(new FlowLayout());
for (int i = 0; i < 31; i++) {
channels[i] = new EqualiserChannel(frequencies[i]);
inner.add(channels[i]);
}
add(inner, BorderLayout.CENTER);
JButton smooth = new JButton("Smooth curve");
smooth.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Float ave[] = new Float[31];
for (int i = 1; i < 30; i++) {
ave[i] = (channels[i-1].getValue() + channels[i].getValue() + channels[i+1].getValue()) / 3.0f;
}
for (int i = 1; i < 30; i++) {
channels[i].setValue(ave[i]);
}
}
});
JButton def = new JButton("Set as default");
def.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 31; i++) {
Options.set("audio.eq." + i, channels[i].getValue());
}
}
});
JButton load = new JButton("Load from default");
load.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 31; i++) {
channels[i].setValue(Options.getFloat("audio.eq." + i));
}
}
});
JPanel buttons = new JPanel();
buttons.setLayout(new FlowLayout());
buttons.add(smooth);
buttons.add(def);
buttons.add(load);
add(buttons, BorderLayout.SOUTH);
}
public float getChannel(int c) {
return channels[c].getValue();
}
public void setChannel(int c, float v) {
channels[c].setValue(v);
}
public void apply(IIRControls c, int chans) {
for (int i = 0; i < 31; i++) {
c.setBandDbValue(i, 0, channels[i].getValue());
if (chans == 2) {
c.setBandDbValue(i, 1, channels[i].getValue());
}
}
}
public String getName() {
return name;
}
}

View File

@@ -1,96 +0,0 @@
package uk.co.majenko.audiobookrecorder;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.nio.file.*;
import javax.swing.tree.*;
import javax.sound.sampled.*;
public class EqualiserChannel extends JPanel {
float value;
JSlider slider;
JTextField textbox;
JLabel frequency;
public EqualiserChannel(double freq) {
super();
value = 0;
slider = new JSlider(-120, 120, 0);
textbox = new JTextField();
String suffix = "Hz";
if (freq > 1000) {
freq /= 1000;
suffix = "kHz";
}
String ftxt = String.format("%.4f", freq);
while (ftxt.endsWith("0")) {
ftxt = ftxt.substring(0, ftxt.length() - 1);
}
if (ftxt.endsWith(".")) {
ftxt = ftxt.substring(0, ftxt.length() - 1);
}
frequency = new JLabel(ftxt + suffix);
setLayout(new BorderLayout());
add(frequency, BorderLayout.NORTH);
slider.setOrientation(SwingConstants.VERTICAL);
add(slider, BorderLayout.CENTER);
textbox = new JTextField("0.0");
add(textbox, BorderLayout.SOUTH);
textbox.setPreferredSize(new Dimension(40, 20));
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
value = (float)slider.getValue() / 10.0f;
textbox.setText(String.format("%.1f", value));
}
});
textbox.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
textbox.selectAll();
}
public void focusLost(FocusEvent e) {
value = Utils.s2f(textbox.getText());
if (value < -12f) value = -12f;
if (value > 12f) value = 12f;
slider.setValue((int)(value * 10));
textbox.setText(String.format("%.1f", value));
}
});
textbox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
value = Utils.s2f(textbox.getText());
if (value < -12f) value = -12f;
if (value > 12f) value = 12f;
slider.setValue((int)(value * 10));
textbox.setText(String.format("%.1f", value));
}
});
}
public float getValue() {
return value;
}
public void setValue(float v) {
value = v;
slider.setValue((int)(value * 10));
textbox.setText(String.format("%.1f", value));
}
}

View File

@@ -27,6 +27,8 @@ public class FlashPanel extends JPanel {
public void setFlash(boolean f) {
flash = f;
col = true;
for (Component o : getComponents()) {
((JComponent)o).setVisible(!f);
}
@@ -42,7 +44,7 @@ public class FlashPanel extends JPanel {
if (col) {
g.setColor(Color.RED);
} else {
g.setColor(Color.BLACK);
g.setColor(Color.GREEN);
}
Dimension d = getSize();
g.fillRect(0, 0, d.width, d.height);

View File

@@ -1,83 +0,0 @@
package uk.co.majenko.audiobookrecorder;
import java.util.*;
import java.util.concurrent.*;
import javax.swing.*;
import java.awt.*;
import java.util.Timer;
public class HavenQueue extends JPanel {
ConcurrentLinkedQueue<Sentence> sentenceList = new ConcurrentLinkedQueue<Sentence>();
Timer timer = new Timer();
Sentence currentSentence = null;
JLabel count;
public HavenQueue() {
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 30000);
count = new JLabel("Haven queue: 0");
setLayout(new BorderLayout());
add(count, BorderLayout.CENTER);
count.setOpaque(false);
setOpaque(false);
count.setForeground(Color.WHITE);
}
public void processQueue() {
count.setText("Haven queue: " + sentenceList.size());
if (currentSentence == null) {
// Grab a new sentence to process.
currentSentence = sentenceList.poll();
if (currentSentence != null) {
if (!currentSentence.postHavenData()) { // Failed. Add to the end of the queue and wait a bit
submit(currentSentence);
currentSentence = null;
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 30000);
return;
}
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 5000);
return;
}
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 5000);
return;
}
if (currentSentence != null) {
currentSentence.processPendingHaven();
int status = currentSentence.getHavenStatus();
switch (status) {
case 0: // Um... not running...?
currentSentence = null;
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 30000);
return;
case 1: // Still processing...
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 5000);
return;
case 2: // Finished
currentSentence = null;
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 30000);
return;
case 3: // Failed
currentSentence = null;
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 30000);
return;
}
}
timer.schedule(new TimerTask() { public void run() { processQueue(); }}, 30000);
}
public void submit(Sentence s) {
s.setOverrideText("[queued...]");
AudiobookRecorder.window.bookTreeModel.reload(s);
sentenceList.add(s);
count.setText("Haven queue: " + sentenceList.size());
}
}

View File

@@ -33,4 +33,9 @@ public class Icons {
static public final ImageIcon dollar = new ImageIcon(Icons.class.getResource("icons/dollar.png"));
static public final ImageIcon attention = new ImageIcon(Icons.class.getResource("icons/attention.png"));
static public final ImageIcon normalize = new ImageIcon(Icons.class.getResource("icons/normalize.png"));
static public final ImageIcon split = new ImageIcon(Icons.class.getResource("icons/split.png"));
static public final ImageIcon cut = new ImageIcon(Icons.class.getResource("icons/cut.png"));
static public final ImageIcon docut = new ImageIcon(Icons.class.getResource("icons/do-cut.png"));
static public final ImageIcon playto = new ImageIcon(Icons.class.getResource("icons/play-to.png"));
static public final ImageIcon disable = new ImageIcon(Icons.class.getResource("icons/disable-effects.png"));
}

View File

@@ -0,0 +1,103 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public class LFO implements Effect {
double phase;
double frequency;
double depth;
double sampleRate;
double sampleStep;
int waveform;
double duty;
int mode;
public static final int SINE = 0;
public static final int COSINE = 1;
public static final int SQUARE = 2;
public static final int TRIANGLE = 3;
public static final int SAWTOOTH = 4;
public static final int ADD = 0;
public static final int REPLACE = 1;
public LFO(double f, double d) {
this(f, d, 0, SINE, Math.PI, REPLACE);
}
public LFO(double f, double d, double p) {
this(f, d, p, SINE, Math.PI, REPLACE);
}
public LFO(double f, double d, double p, int w) {
this(f, d, p, w, Math.PI, REPLACE);
}
public LFO(double f, double d, double p, int w, double dty) {
this(f, d, p, w, dty, REPLACE);
}
public LFO(double f, double d, double p, int w, double dty, int m) {
frequency = f;
depth = d;
phase = p;
waveform = w;
duty = dty;
mode = m;
}
public void process(double[][] samples) {
for (double[] sample : samples) {
double v = 0;
switch (waveform) {
case SINE: v = Math.sin(phase); break;
case COSINE: v = Math.cos(phase); break;
case SQUARE: v = (phase > duty) ? 1d : 0d; break;
case TRIANGLE: v = (phase < Math.PI) ? (phase / Math.PI) : (1d - ((phase - Math.PI) / Math.PI)); break;
case SAWTOOTH: v = (phase / (Math.PI*2d)); break;
}
phase += sampleStep;
if (phase > (Math.PI * 2d)) {
phase -= (Math.PI * 2d);
}
// Multiply it by the gain factor
v *= depth;
// Apply it to the sample
switch (mode) {
case REPLACE:
sample[Sentence.LEFT] = (sample[Sentence.LEFT] * v);
sample[Sentence.RIGHT] = (sample[Sentence.RIGHT] * v);
break;
case ADD:
sample[Sentence.LEFT] += (sample[Sentence.LEFT] * v);
sample[Sentence.RIGHT] += (sample[Sentence.RIGHT] * v);
break;
}
}
}
public String getName() { return "Low Frequency Oscillator (" + frequency + " Hz, " + (depth * 100d) + "%)"; }
public ArrayList<Effect> getChildEffects() { return null; }
public void dump() {
System.out.println(getName());
}
public void init(double sr) {
sampleRate = sr;
// Number of samples that make up one cycle of the LFO
double oneCycle = sampleRate / frequency;
// Amount to increase each step
sampleStep = (Math.PI * 2d) / oneCycle;
}
public String toString() { return getName(); }
}

View File

@@ -14,9 +14,14 @@ public class MainToolBar extends JToolBar {
JButtonSpacePlay recordRoomNoise;
JButtonSpacePlay playSentence;
JButtonSpacePlay playonSentence;
JButtonSpacePlay playtoSentence;
JButtonSpacePlay stopPlaying;
JButtonSpacePlay eq;
JToggleButton mic;
JToggleButtonSpacePlay mic;
JComboBox<String> playbackSpeed;
JToggleButtonSpacePlay disableEffects;
AudiobookRecorder root;
@@ -78,6 +83,14 @@ public class MainToolBar extends JToolBar {
});
add(playonSentence);
playtoSentence = new JButtonSpacePlay(Icons.playto, "Play sentence to cut", new ActionListener() {
public void actionPerformed(ActionEvent e) {
root.playToSelectedSentence();
}
});
add(playtoSentence);
playtoSentence.setEnabled(false);
stopPlaying = new JButtonSpacePlay(Icons.stop, "Stop playing", new ActionListener() {
public void actionPerformed(ActionEvent e) {
root.stopPlaying();
@@ -86,9 +99,10 @@ public class MainToolBar extends JToolBar {
add(stopPlaying);
addSeparator();
eq = new JButtonSpacePlay(Icons.eq, "Equaliser", new ActionListener() {
eq = new JButtonSpacePlay(Icons.eq, "Reload Effects", new ActionListener() {
public void actionPerformed(ActionEvent e) {
root.showEqualiser();
root.loadEffects();
CacheManager.purgeCache();
}
});
@@ -117,11 +131,56 @@ public class MainToolBar extends JToolBar {
}
}
});
add(mic);
addSeparator();
disableEffects = new JToggleButtonSpacePlay(Icons.disable, "Disable effects", new ActionListener() {
Color bgCol = null;
public void actionPerformed(ActionEvent e) {
JToggleButton b = (JToggleButton)e.getSource();
if (b.isSelected()) {
root.setEffectsEnabled(false);
bgCol = b.getBackground();
b.setBackground(Color.RED);
} else {
root.setEffectsEnabled(true);
if (bgCol != null) {
b.setBackground(bgCol);
}
}
}
});
add(disableEffects);
addSeparator();
add(new JLabel("Playback speed: "));
playbackSpeed = new JComboBox<String>(new String[] {
"0.75x",
"1.00x",
"1.25x",
"1.50x",
"1.75x"
});
playbackSpeed.setFocusable(false);
playbackSpeed.setSelectedIndex(1);
add(playbackSpeed);
setFloatable(false);
}
public void enablePlayTo(boolean b) {
playtoSentence.setEnabled(b);
}
public float getPlaybackSpeed() {
int v = playbackSpeed.getSelectedIndex();
return 0.75f + (0.25f * v);
}
}

View File

@@ -8,6 +8,7 @@ import java.awt.event.*;
import java.util.*;
import java.util.prefs.*;
import java.io.*;
import javax.swing.tree.*;
public class Options extends JDialog {
@@ -15,12 +16,16 @@ public class Options extends JDialog {
GridBagConstraints constraint;
public static ArrayList<EffectGroup> effectChains;
JComboBox<KVPair> mixerList;
JComboBox<KVPair> playbackList;
JComboBox<KVPair> channelList;
JComboBox<KVPair> rateList;
JComboBox<KVPair> bitDepth;
JComboBox<KVPair> trimMethod;
JComboBox<KVPair> fftBlockSize;
JComboBox<KVPair> playbackBlockSize;
JTextField storageFolder;
JTextField archiveFolder;
JSpinner preChapterGap;
@@ -28,22 +33,22 @@ public class Options extends JDialog {
JSpinner postSentenceGap;
JSpinner shortSentenceGap;
JSpinner postParagraphGap;
JSpinner postSectionGap;
JTextField ffmpegLocation;
JComboBox<KVPair> bitRate;
JComboBox<KVPair> channels;
JComboBox<KVPair> exportRate;
JCheckBox enableParsing;
JSpinner cacheSize;
JSpinner fftThreshold;
JSpinner etherealIterations;
JSpinner etherealAttenuation;
JSpinner etherealOffset;
JTextField havenApiKey;
JTextField externalEditor;
Equaliser equaliser;
JTextArea startupScript;
ArrayList<JTextField[]> processorList;
@@ -294,10 +299,13 @@ public class Options extends JDialog {
rateList = addDropdown(optionsPanel, "Sample rate:", getSampleRateList(), get("audio.recording.samplerate"));
bitDepth = addDropdown(optionsPanel, "Sample resolution:", getResolutionList(), get("audio.recording.resolution"));
trimMethod = addDropdown(optionsPanel, "Auto-trim method:", getTrimMethods(), get("audio.recording.trim"));
fftThreshold = addSpinner(optionsPanel, "FFT threshold:", 0, 100, 1, getInteger("audio.recording.trim.fft"), "");
fftBlockSize = addDropdown(optionsPanel, "FFT Block size:", getFFTBlockSizes(), get("audio.recording.trim.blocksize"));
addSeparator(optionsPanel);
playbackList = addDropdown(optionsPanel, "Playback device:", getPlaybackMixerList(), get("audio.playback.device"));
playbackBlockSize = addDropdown(optionsPanel, "Playback Block size:", getPlaybackBlockSizes(), get("audio.playback.blocksize"));
addSeparator(optionsPanel);
storageFolder = addFilePath(optionsPanel, "Storage folder:", get("path.storage"), true);
archiveFolder = addFilePath(optionsPanel, "Archive folder:", get("path.archive"), true);
@@ -309,34 +317,47 @@ public class Options extends JDialog {
postSentenceGap = addSpinner(optionsPanel, "Default post-sentence gap:", 0, 5000, 100, getInteger("catenation.post-sentence"), "ms");
shortSentenceGap = addSpinner(optionsPanel, "Short post-sentence gap:", 0, 5000, 100, getInteger("catenation.short-sentence"), "ms");
postParagraphGap = addSpinner(optionsPanel, "Default post-paragraph gap:", 0, 5000, 100, getInteger("catenation.post-paragraph"), "ms");
postSectionGap = addSpinner(optionsPanel, "Default post-section gap:", 0, 5000, 100, getInteger("catenation.post-section"), "ms");
addSeparator(optionsPanel);
ffmpegLocation = addFilePath(optionsPanel, "FFMPEG location:", get("path.ffmpeg"), false);
bitRate = addDropdown(optionsPanel, "Export bitrate:", getBitrates(), get("audio.export.bitrate"));
channels = addDropdown(optionsPanel, "Export channels:", getChannelCountList(), get("audio.export.channels"));
exportRate = addDropdown(optionsPanel, "Export sample rate:", getSampleRateList(), get("audio.export.samplerate"));
addSeparator(optionsPanel);
enableParsing = addCheckBox(optionsPanel, "Enable automatic speech-to-text submission", getBoolean("process.haven.auto"));
havenApiKey = addTextField(optionsPanel, "Haven OnDemand API Key", get("process.haven.apikey"));
enableParsing = addCheckBox(optionsPanel, "Enable automatic sphinx speech-to-text (**SLOW**)", getBoolean("process.sphinx"));
addSeparator(optionsPanel);
externalEditor = addTextField(optionsPanel, "External Editor Command", get("editor.external"));
addSeparator(optionsPanel);
cacheSize = addSpinner(optionsPanel, "Cache size:", 0, 5000, 1, getInteger("cache.size"), "");
cacheSize = addSpinner(optionsPanel, "Cache size:", 2, 100, 1, getInteger("cache.size"), "");
addSeparator(optionsPanel);
tabs.add("Options", new JScrollPane(optionsPanel));
equaliser = new Equaliser("Default");
for (int i = 0; i < 31; i++) {
equaliser.setChannel(i, Options.getFloat("audio.eq." + i));
}
tabs.add("Default EQ", new JScrollPane(equaliser));
JPanel effectChains = new JPanel();
effectChains.setLayout(new BorderLayout());
JPanel effectDetails = new JPanel() {
public Dimension getPreferredSize() {
return new Dimension(200, 400);
}
};
DefaultTreeModel m = new DefaultTreeModel(new DefaultMutableTreeNode("Effect Chains"));
JTree effectChainTree = new JTree(m);
effectChains.add(effectChainTree, BorderLayout.CENTER);
effectChains.add(effectDetails, BorderLayout.EAST);
tabs.add("Effects Chains", new JScrollPane(effectChains));
JPanel startScript = new JPanel();
startScript.setLayout(new BorderLayout());
@@ -440,6 +461,7 @@ public class Options extends JDialog {
setVisible(true);
}
@SuppressWarnings("unchecked")
static KVPair<String, String>[] getRecordingMixerList() {
TreeSet<KVPair<String, String>> list = new TreeSet<KVPair<String, String>>();
@@ -549,59 +571,31 @@ public class Options extends JDialog {
} else {
defaultPrefs.put("audio.playback.device", "");
}
defaultPrefs.put("audio.recording.trim.blocksize", "4096");
defaultPrefs.put("audio.playback.blocksize", "4096");
defaultPrefs.put("catenation.pre-chapter", "1000");
defaultPrefs.put("catenation.post-chapter", "1500");
defaultPrefs.put("catenation.post-sentence", "1000");
defaultPrefs.put("catenation.short-sentence", "100");
defaultPrefs.put("catenation.post-paragraph", "2000");
defaultPrefs.put("catenation.post-section", "3000");
defaultPrefs.put("audio.recording.trim.fft", "10");
defaultPrefs.put("path.storage", (new File(System.getProperty("user.home"), "Recordings")).toString());
defaultPrefs.put("path.archive", (new File(new File(System.getProperty("user.home"), "Recordings"),"archive")).toString());
defaultPrefs.put("path.ffmpeg", "");
defaultPrefs.put("audio.export.bitrate", "256000");
defaultPrefs.put("audio.export.channels", "2");
defaultPrefs.put("audio.export.samplerate", "44100");
defaultPrefs.put("process.sphinx", "false");
defaultPrefs.put("process.haven.apikey", "");
defaultPrefs.put("editor.external", "");
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");
defaultPrefs.put("scripts.startup", "");
defaultPrefs.put("effects.ethereal.offset", "50");
@@ -639,6 +633,14 @@ public class Options extends JDialog {
return 0;
}
public static Double getDouble(String key) {
try {
Double f = Double.parseDouble(get(key));
return f;
} catch (Exception e) {
}
return 0.0d;
}
public static Float getFloat(String key) {
try {
Float f = Float.parseFloat(get(key));
@@ -708,21 +710,21 @@ public class Options extends JDialog {
set("catenation.post-sentence", postSentenceGap.getValue());
set("catenation.short-sentence", shortSentenceGap.getValue());
set("catenation.post-paragraph", postParagraphGap.getValue());
set("catenation.post-section", postSectionGap.getValue());
set("audio.export.bitrate", ((KVPair)bitRate.getSelectedItem()).key);
set("audio.export.channels", ((KVPair)channels.getSelectedItem()).key);
set("audio.export.samplerate", ((KVPair)exportRate.getSelectedItem()).key);
set("process.sphinx", enableParsing.isSelected());
set("process.haven.apikey", havenApiKey.getText());
set("editor.external", externalEditor.getText());
set("cache.size", cacheSize.getValue());
set("audio.recording.trim.fft", fftThreshold.getValue());
set("audio.recording.trim.blocksize", ((KVPair)fftBlockSize.getSelectedItem()).key);
set("audio.playback.blocksize", ((KVPair)playbackBlockSize.getSelectedItem()).key);
set("effects.ethereal.offset", etherealOffset.getValue());
set("effects.ethereal.iterations", etherealIterations.getValue());
set("effects.ethereal.attenuation", etherealAttenuation.getValue());
for (int i = 0; i < 31; i++) {
set("audio.eq." + i, equaliser.getChannel(i));
}
set("scripts.startup", startupScript.getText());
int procNo = 0;
@@ -778,15 +780,90 @@ public class Options extends JDialog {
}
public static KVPair[] getResolutionList() {
KVPair[] pairs = new KVPair[1];
KVPair[] pairs = new KVPair[2];
pairs[0] = new KVPair<String, String>("16", "16 Bit");
pairs[1] = new KVPair<String, String>("24", "24 Bit");
return pairs;
}
public static KVPair[] getTrimMethods() {
KVPair[] pairs = new KVPair[2];
pairs[0] = new KVPair<String, String>("peak", "Peak Amplitude");
pairs[1] = new KVPair<String, String>("fft", "FFT Analysis");
KVPair[] pairs = new KVPair[3];
pairs[0] = new KVPair<String, String>("none", "None");
pairs[1] = new KVPair<String, String>("peak", "Peak Amplitude");
pairs[2] = new KVPair<String, String>("fft", "FFT Analysis");
return pairs;
}
public static KVPair[] getFFTBlockSizes() {
KVPair[] pairs = new KVPair[8];
pairs[0] = new KVPair<String, String>("1024", "1024");
pairs[1] = new KVPair<String, String>("2048", "2048");
pairs[2] = new KVPair<String, String>("4096", "4096");
pairs[3] = new KVPair<String, String>("8192", "8192");
pairs[4] = new KVPair<String, String>("16384", "16384");
pairs[5] = new KVPair<String, String>("32768", "32768");
pairs[6] = new KVPair<String, String>("65536", "65537");
pairs[7] = new KVPair<String, String>("131072", "131072");
return pairs;
}
public static KVPair[] getPlaybackBlockSizes() {
KVPair[] pairs = new KVPair[8];
pairs[0] = new KVPair<String, String>("1024", "1024");
pairs[1] = new KVPair<String, String>("2048", "2048");
pairs[2] = new KVPair<String, String>("4096", "4096");
pairs[3] = new KVPair<String, String>("8192", "8192");
pairs[4] = new KVPair<String, String>("16384", "16384");
pairs[5] = new KVPair<String, String>("32768", "32768");
pairs[6] = new KVPair<String, String>("65536", "65537");
pairs[7] = new KVPair<String, String>("131072", "131072");
return pairs;
}
public static void createEffectChains() {
effectChains = new ArrayList<EffectGroup>();
for (int i = 0; i < 999999; i++) {
if (get("effects." + i + ".name") == null) {
EffectGroup e = new EffectGroup(get("effects." + i + ".name"));
for (int j = 0; i < 999999; j++) {
String type = get("effects." + i + ".children." + j + ".type");
if (type == null) break;
if (type.equals("biquad")) {
int bqt = getInteger("effects." + i + ".children." + j + ".filtertype");
double fc = getDouble("effects." + i + ".children." + j + ".fc");
double q = getDouble("effects." + i + ".children." + j + ".q");
double gain = getDouble("effects." + i + ".children." + j + ".gain");
Biquad b = new Biquad(bqt, fc, q, gain);
e.addEffect(b);
continue;
}
if (type.equals("amplifier")) {
double gain = getDouble("effects." + i + ".children." + j + ".gain");
Amplifier a = new Amplifier(gain);
e.addEffect(a);
continue;
}
if (type.equals("delayline")) {
DelayLine l = new DelayLine();
for (int c = 0; c < 999999; c++) {
if (get("effects." + i + ".children." + j + ".lines." + c + ".samples") == null) break;
int samples = getInteger("effects." + i + ".children." + j + ".lines." + c + ".samples");
double gain = getDouble("effects." + i + ".children." + j + ".lines." + c + ".gain");
l.addDelayLine(samples, gain);
}
e.addEffect(l);
continue;
}
}
effectChains.add(e);
break;
}
}
}
}

View File

@@ -0,0 +1,52 @@
package uk.co.majenko.audiobookrecorder;
import java.util.ArrayList;
public class Pan implements Effect {
double pan;
public Pan() {
pan = 0.0d;
}
public Pan(double p) {
pan = p;
}
public String getName() {
return "Pan (" + pan + ")";
}
public ArrayList<Effect> getChildEffects() {
return null;
}
public void process(double[][] samples) {
for (double[] sample : samples) {
if (pan < 0) {
double p = 1 + pan;
sample[Sentence.RIGHT] *= p;
} else {
double p = 1 - pan;
sample[Sentence.LEFT] *= p;
}
}
}
public double getPan() {
return pan;
}
public void setPan(double p) {
pan = p;
}
public String toString() {
return getName();
}
public void dump() {
System.out.println(toString());
}
public void init(double sf) {
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -63,4 +63,17 @@ public class Utils {
}
}
}
static long millis = System.currentTimeMillis();
public static void report(String tag) {
long t = System.currentTimeMillis();
long d = t - millis;
millis = t;
System.err.println(String.format("%10d - %10s : %8d | %8d | %8d", d, tag,
Runtime.getRuntime().totalMemory(),
Runtime.getRuntime().maxMemory(),
Runtime.getRuntime().freeMemory()
));
}
}

View File

@@ -9,7 +9,7 @@ import javax.sound.sampled.*;
public class Waveform extends JPanel implements MouseListener, MouseMotionListener {
int[] samples = null;
double[][] samples = null;
int leftMarker = 0;
int rightMarker = 0;
@@ -21,6 +21,11 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
int leftAltMarker = 0;
int rightAltMarker = 0;
int cutEntry = 0;
int cutExit = 0;
boolean displayCut = false;
boolean displaySplit = false;
int dragging = 0;
int step = 1;
@@ -62,12 +67,15 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
g.drawLine(x, 0, x, h);
}
int h2 = h/2;
int db3 = (int) (h2 * 0.708);
for (int x = 0; x < w; x += 4) {
g.drawLine(x, h/4, x, h/4);
g.drawLine(x, h/4*3, x, h/4*3);
g.drawLine(x, h2 + db3, x, h2 + db3);
g.drawLine(x, h2 - db3, x, h2 - db3);
}
int scale = 32768/(h/2);
double scale = (h/2);
if (samples != null) {
@@ -81,15 +89,16 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
for (int n = 0; n < w; n++) {
int hcnt = 0;
long have = 0;
int hmax = 0;
double have = 0;
double hmax = 0;
int lcnt = 0;
int lave = 0;
int lmax = 0;
double lave = 0;
double lmax = 0;
for (int o = 0; o < step; o++) {
int sample = samples[offset + (n * step) + o];
if (offset + (n * step) + o >= samples.length) break;
double sample = (samples[offset + (n * step) + o][Sentence.LEFT] + samples[offset + (n * step) + o][Sentence.RIGHT]) / 2d;
if (sample >= 0) {
have += sample;
hcnt++;
@@ -107,30 +116,30 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
boolean clip = false;
if (lmax > 32000) { // -3dB == 23198?
if (lmax > 0.708) { // -3dB == 23198?
clip = true;
}
if (hmax > 32000) { // -3dB
if (hmax > 0.708) { // -3dB
clip = true;
}
hmax /= scale;
lmax /= scale;
have /= scale;
lave /= scale;
hmax *= scale;
lmax *= scale;
have *= scale;
lave *= scale;
if (clip) {
g.setColor(new Color(200, 20, 0));
} else {
g.setColor(new Color(0, 20, 200));
}
g.drawLine(n, h/2 + lmax, n, h/2 - hmax);
g.drawLine(n, (int)(h/2 + lmax), n, (int)(h/2 - hmax));
g.setColor(new Color(0, 100, 255));
g.drawLine(n, h/2 + (int)lave, n, h/2 - (int)have);
g.drawLine(n, (int)(h/2 + lave), n, (int)(h/2 - have));
}
g.setColor(new Color(255, 0, 0, 32));
g.setColor(new Color(255, 0, 0, 64));
g.fillRect(0, 0, (leftAltMarker - offset)/step, h);
g.fillRect((rightAltMarker - offset)/step, 0, (num - rightAltMarker) / step , h);
@@ -142,6 +151,19 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
g.drawLine((leftMarker - offset)/step, 0, (leftMarker - offset)/step, h);
g.drawLine((rightMarker - offset)/step, 0, (rightMarker - offset)/step, h);
if (displayCut || displaySplit) {
g.setColor(new Color(0, 255, 255));
g.drawLine((cutEntry - offset)/step, 0, (cutEntry - offset)/step, h);
}
if (displayCut) {
g.setColor(new Color(0, 255, 255));
g.drawLine((cutExit - offset)/step, 0, (cutExit - offset)/step, h);
g.setColor(new Color(0, 255, 255, 80));
g.fillRect((cutEntry - offset)/step, 0, ((cutExit - offset) - (cutEntry - offset))/step , h);
}
g.setColor(new Color(0, 255, 255));
for (int i = 0; i < h; i += 2) {
g.drawLine((playMarker - offset) / step, i, (playMarker - offset) / step, i);
@@ -186,9 +208,11 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
repaint();
}
public void setData(int[] s) {
public void setData(double[][] s) {
samples = s;
playMarker = 0;
displayCut = false;
displaySplit = false;
repaint();
}
@@ -218,6 +242,19 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
dragging = 2;
return;
}
if (displayCut || displaySplit) {
if ((x >= ((cutEntry - offset)/step) - 10) && (x <= ((cutEntry - offset)/step) + 10)) {
dragging = 3;
return;
}
}
if (displayCut) {
if ((x >= ((cutExit - offset)/step) - 10) && (x <= ((cutExit - offset)/step) + 10)) {
dragging = 4;
return;
}
}
}
public void mouseReleased(MouseEvent e) {
@@ -248,6 +285,19 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
return;
}
if (displayCut || displaySplit) {
if ((x >= ((cutEntry - offset)/step) - 10) && (x <= ((cutEntry - offset)/step) + 10)) {
setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
return;
}
}
if (displayCut) {
if ((x >= ((cutExit - offset)/step) - 10) && (x <= ((cutExit - offset)/step) + 10)) {
setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
return;
}
}
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
@@ -267,6 +317,18 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
if (rightMarker < leftMarker) {
rightMarker = leftMarker;
}
} else if (dragging == 3) {
cutEntry = (x * step) + offset;
if (displayCut) {
if (cutEntry > cutExit) {
cutEntry = cutExit;
}
}
} else if (dragging == 4) {
cutExit = (x * step) + offset;
if (cutExit < cutEntry) {
cutExit = cutEntry;
}
}
repaint();
@@ -296,4 +358,33 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
playMarker = leftAltMarker + m;
repaint();
}
public void setDisplayCut(boolean c) {
displayCut = c;
displaySplit = false;
if (displayCut) {
int d = rightMarker - leftMarker;
cutEntry = leftMarker + (d / 3);
cutExit = leftMarker + (d / 3 * 2);
}
repaint();
}
public void setDisplaySplit(boolean c) {
displayCut = false;
displaySplit = c;
if (displaySplit) {
int d = rightMarker - leftMarker;
cutEntry = leftMarker + (d / 2);
}
repaint();
}
public int getCutStart() {
return cutEntry;
}
public int getCutEnd() {
return cutExit;
}
}