Implement wheel over waveform to change gain
This commit is contained in:
@@ -439,6 +439,16 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sampleWaveform.addMouseWheelListener(new MouseWheelListener() {
|
||||||
|
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||||
|
if (selectedSentence == null) return;
|
||||||
|
if (selectedSentence.isLocked()) return;
|
||||||
|
int val = ((int)gainPercent.getValue()) - e.getWheelRotation();
|
||||||
|
if (val < 1) val = 1;
|
||||||
|
gainPercent.setValue(val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
sampleWaveform.addMarkerDragListener(new MarkerDragListener() {
|
sampleWaveform.addMarkerDragListener(new MarkerDragListener() {
|
||||||
public void leftMarkerMoved(MarkerDragEvent e) {
|
public void leftMarkerMoved(MarkerDragEvent e) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
@@ -474,7 +484,6 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (selectedSentence != null) {
|
if (selectedSentence != null) {
|
||||||
selectedSentence.autoTrimSampleFFT();
|
selectedSentence.autoTrimSampleFFT();
|
||||||
sampleWaveform.setData(selectedSentence.getDoubleAudioData(effectsEnabled));
|
|
||||||
sampleWaveform.setMarkers(selectedSentence.getStartOffset(), selectedSentence.getEndOffset());
|
sampleWaveform.setMarkers(selectedSentence.getStartOffset(), selectedSentence.getEndOffset());
|
||||||
sampleWaveform.setAltMarkers(selectedSentence.getStartCrossing(), selectedSentence.getEndCrossing());
|
sampleWaveform.setAltMarkers(selectedSentence.getStartCrossing(), selectedSentence.getEndCrossing());
|
||||||
postSentenceGap.setValue(selectedSentence.getPostGap());
|
postSentenceGap.setValue(selectedSentence.getPostGap());
|
||||||
@@ -488,7 +497,6 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (selectedSentence != null) {
|
if (selectedSentence != null) {
|
||||||
selectedSentence.autoTrimSamplePeak();
|
selectedSentence.autoTrimSamplePeak();
|
||||||
sampleWaveform.setData(selectedSentence.getDoubleAudioData(effectsEnabled));
|
|
||||||
sampleWaveform.setMarkers(selectedSentence.getStartOffset(), selectedSentence.getEndOffset());
|
sampleWaveform.setMarkers(selectedSentence.getStartOffset(), selectedSentence.getEndOffset());
|
||||||
sampleWaveform.setAltMarkers(selectedSentence.getStartCrossing(), selectedSentence.getEndCrossing());
|
sampleWaveform.setAltMarkers(selectedSentence.getStartCrossing(), selectedSentence.getEndCrossing());
|
||||||
postSentenceGap.setValue(selectedSentence.getPostGap());
|
postSentenceGap.setValue(selectedSentence.getPostGap());
|
||||||
@@ -502,7 +510,8 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (selectedSentence != null) {
|
if (selectedSentence != null) {
|
||||||
selectedSentence.normalize();
|
selectedSentence.normalize();
|
||||||
sampleWaveform.setData(selectedSentence.getDoubleAudioData(effectsEnabled));
|
gainPercent.setValue((int)(selectedSentence.getGain() * 100d));
|
||||||
|
updateWaveform(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -550,7 +559,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
JSpinner ob = (JSpinner)e.getSource();
|
JSpinner ob = (JSpinner)e.getSource();
|
||||||
if (selectedSentence != null) {
|
if (selectedSentence != null) {
|
||||||
selectedSentence.setGain((Integer)ob.getValue() / 100d);
|
selectedSentence.setGain((Integer)ob.getValue() / 100d);
|
||||||
sampleWaveform.setData(selectedSentence.getDoubleAudioData(effectsEnabled));
|
updateWaveform(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -672,7 +681,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
KVPair<String, String> p = effectChain.getItemAt(i);
|
KVPair<String, String> p = effectChain.getItemAt(i);
|
||||||
if (p == null) return;
|
if (p == null) return;
|
||||||
selectedSentence.setEffectChain(p.getKey());
|
selectedSentence.setEffectChain(p.getKey());
|
||||||
updateWaveform();
|
updateWaveform(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2947,6 +2956,10 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Sentence getRoomNoiseSentence() {
|
||||||
|
return roomNoise;
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] getRoomNoise(int ms) {
|
public byte[] getRoomNoise(int ms) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
|
|
||||||
@@ -3461,9 +3474,13 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateWaveform() {
|
public void updateWaveform() {
|
||||||
|
updateWaveform(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateWaveform(boolean force) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (selectedSentence != null) {
|
if (selectedSentence != null) {
|
||||||
if ((sampleWaveform.getId() != null) && (sampleWaveform.getId().equals(selectedSentence.getId()))) return;
|
if ((!force) && (sampleWaveform.getId() != null) && (sampleWaveform.getId().equals(selectedSentence.getId()))) return;
|
||||||
sampleWaveform.setId(selectedSentence.getId());
|
sampleWaveform.setId(selectedSentence.getId());
|
||||||
if (rawAudio.isSelected()) {
|
if (rawAudio.isSelected()) {
|
||||||
sampleWaveform.setData(selectedSentence.getRawAudioData());
|
sampleWaveform.setData(selectedSentence.getRawAudioData());
|
||||||
@@ -3796,17 +3813,17 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
KVPair<String, String> p = effectChain.getItemAt(i);
|
KVPair<String, String> p = effectChain.getItemAt(i);
|
||||||
if (p.getKey().equals(key)) {
|
if (p.getKey().equals(key)) {
|
||||||
effectChain.setSelectedIndex(i);
|
effectChain.setSelectedIndex(i);
|
||||||
updateWaveform();
|
updateWaveform(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effects.get(book.getDefaultEffect()) != null) {
|
if (effects.get(book.getDefaultEffect()) != null) {
|
||||||
setEffectChain(book.getDefaultEffect());
|
setEffectChain(book.getDefaultEffect());
|
||||||
updateWaveform();
|
updateWaveform(true);
|
||||||
} else {
|
} else {
|
||||||
effectChain.setSelectedIndex(0);
|
effectChain.setSelectedIndex(0);
|
||||||
updateWaveform();
|
updateWaveform(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3874,12 +3891,14 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
int a = 0;
|
int a = 0;
|
||||||
for (int i = 0; i < samples[Sentence.LEFT].length; i++) {
|
for (int i = 0; i < samples[Sentence.LEFT].length; i++) {
|
||||||
if ((i < start) || (i > end)) {
|
if ((i < start) || (i > end)) {
|
||||||
croppedSamples[a++] = samples[i];
|
croppedSamples[Sentence.LEFT][a] = samples[Sentence.LEFT][i];
|
||||||
|
croppedSamples[Sentence.RIGHT][a] = samples[Sentence.RIGHT][i];
|
||||||
|
a++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selectedSentence.writeAudioData(croppedSamples);
|
selectedSentence.writeAudioData(croppedSamples);
|
||||||
selectedSentence.autoTrimSample();
|
selectedSentence.autoTrimSample();
|
||||||
updateWaveform();
|
updateWaveform(true);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -3906,9 +3925,13 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
|
|
||||||
for (int i = 0; i < samples[Sentence.LEFT].length; i++) {
|
for (int i = 0; i < samples[Sentence.LEFT].length; i++) {
|
||||||
if (i < at) {
|
if (i < at) {
|
||||||
startSamples[a++] = samples[i];
|
startSamples[Sentence.LEFT][a] = samples[Sentence.LEFT][i];
|
||||||
|
startSamples[Sentence.RIGHT][a] = samples[Sentence.RIGHT][i];
|
||||||
|
a++;
|
||||||
} else {
|
} else {
|
||||||
endSamples[b++] = samples[i];
|
endSamples[Sentence.LEFT][b] = samples[Sentence.LEFT][i];
|
||||||
|
endSamples[Sentence.RIGHT][b] = samples[Sentence.RIGHT][i];
|
||||||
|
b++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3919,7 +3942,7 @@ public class AudiobookRecorder extends JFrame implements DocumentListener {
|
|||||||
selectedSentence.writeAudioData(endSamples);
|
selectedSentence.writeAudioData(endSamples);
|
||||||
selectedSentence.autoTrimSample();
|
selectedSentence.autoTrimSample();
|
||||||
newSentence.autoTrimSample();
|
newSentence.autoTrimSample();
|
||||||
updateWaveform();
|
updateWaveform(true);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
double[][] processedAudio = null;
|
double[][] processedAudio = null;
|
||||||
|
|
||||||
|
double[] fftProfile = null;
|
||||||
|
|
||||||
RecordingThread recordingThread;
|
RecordingThread recordingThread;
|
||||||
|
|
||||||
boolean effectEthereal = false;
|
boolean effectEthereal = false;
|
||||||
@@ -283,6 +285,17 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
autoTrimSampleFFT(false);
|
autoTrimSampleFFT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double bucketDifference(double[] a, double[] b) {
|
||||||
|
double diff = 0d;
|
||||||
|
int l = Math.min(a.length, b.length);
|
||||||
|
for (int i = 0; i < l; i++) {
|
||||||
|
if ((a[i] - b[i]) > diff) {
|
||||||
|
diff = (a[i] - b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
public void autoTrimSampleFFT(boolean useRaw) {
|
public void autoTrimSampleFFT(boolean useRaw) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
crossStartOffset = -1;
|
crossStartOffset = -1;
|
||||||
@@ -297,11 +310,13 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double[] roomNoiseProfile = AudiobookRecorder.window.getRoomNoiseSentence().getFFTProfile();
|
||||||
|
|
||||||
int fftSize = Options.getInteger("audio.recording.trim.blocksize");
|
int fftSize = Options.getInteger("audio.recording.trim.blocksize");
|
||||||
|
|
||||||
int blocks = samples[LEFT].length / fftSize + 1;
|
int blocks = samples[LEFT].length / fftSize + 1;
|
||||||
|
|
||||||
int[] intens = new int[blocks];
|
double[] intens = new double[blocks];
|
||||||
int block = 0;
|
int block = 0;
|
||||||
|
|
||||||
for (int i = 0; i < samples[LEFT].length; i+= fftSize) {
|
for (int i = 0; i < samples[LEFT].length; i+= fftSize) {
|
||||||
@@ -319,31 +334,20 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double[] buckets = FFT.fft(real, imag, true);
|
double[] buckets = FFT.fft(real, imag, true);
|
||||||
double av = 0;
|
|
||||||
for (int j = 1; j < fftSize/2; j++) {
|
|
||||||
av += Math.abs(buckets[j]);
|
|
||||||
}
|
|
||||||
av /= (fftSize / 2);
|
|
||||||
|
|
||||||
intens[block] = 0;
|
|
||||||
|
|
||||||
for (int j = 2; j < fftSize; j += 2) {
|
intens[block] = bucketDifference(buckets, roomNoiseProfile);
|
||||||
double d = Math.abs(av - buckets[j]);
|
|
||||||
if (d > 0.05) {
|
|
||||||
intens[block]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
block++;
|
block++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int limit = Options.getInteger("audio.recording.trim.fft");
|
double limit = (double)(Options.getInteger("audio.recording.trim.fft"));
|
||||||
|
|
||||||
// Find first block with > 1 intensity and subtract one.
|
// Find first block with > 1 intensity and subtract one.
|
||||||
|
|
||||||
int start = 0;
|
int start = 0;
|
||||||
for (int i = 0; i < blocks; i++) {
|
for (int i = 0; i < blocks; i++) {
|
||||||
if (intens[i] > limit) break;
|
if (intens[i] >= (limit / 100.0)) break;
|
||||||
start = i;
|
start = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,7 +362,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
int end = blocks - 1;
|
int end = blocks - 1;
|
||||||
// And last block with > 1 intensity and add one.
|
// And last block with > 1 intensity and add one.
|
||||||
for (int i = blocks-1; i >= 0; i--) {
|
for (int i = blocks-1; i >= 0; i--) {
|
||||||
if (intens[i] > limit) break;
|
if (intens[i] >= (limit / 100)) break;
|
||||||
end = i;
|
end = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,6 +384,50 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
reloadTree();
|
reloadTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double[] getFFTProfile() {
|
||||||
|
Debug.trace();
|
||||||
|
if (fftProfile != null) return fftProfile;
|
||||||
|
|
||||||
|
double[][] samples = getProcessedAudioData();
|
||||||
|
if (samples == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fftSize = Options.getInteger("audio.recording.trim.blocksize");
|
||||||
|
|
||||||
|
fftProfile = new double[fftSize / 2];
|
||||||
|
for (int j = 1; j < fftSize/2; j++) {
|
||||||
|
fftProfile[j] = 0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < samples[LEFT].length; i+= fftSize) {
|
||||||
|
double[] real = new double[fftSize];
|
||||||
|
double[] imag = new double[fftSize];
|
||||||
|
|
||||||
|
for (int j = 0; j < fftSize; j++) {
|
||||||
|
if (i + j < samples[LEFT].length) {
|
||||||
|
real[j] = (samples[LEFT][i+j] + samples[RIGHT][i+j]) / 2d;
|
||||||
|
imag[j] = 0;
|
||||||
|
} else {
|
||||||
|
real[j] = 0;
|
||||||
|
imag[j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double[] buckets = FFT.fft(real, imag, true);
|
||||||
|
|
||||||
|
for (int j = 1; j < fftSize/2; j++) {
|
||||||
|
fftProfile[j] += Math.abs(buckets[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 1; j < fftSize/2; j++) {
|
||||||
|
fftProfile[j] /= (double)(fftSize / 2d);
|
||||||
|
}
|
||||||
|
return fftProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void autoTrimSamplePeak() {
|
public void autoTrimSamplePeak() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
autoTrimSamplePeak(false);
|
autoTrimSamplePeak(false);
|
||||||
@@ -873,12 +921,12 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
int gint = (int)(g * 100d);
|
int gint = (int)(g * 100d);
|
||||||
int gainint = (int)(gain * 100d);
|
int gainint = (int)(gain * 100d);
|
||||||
|
gain = g;
|
||||||
if (gint != gainint) {
|
if (gint != gainint) {
|
||||||
CacheManager.removeFromCache(this);
|
CacheManager.removeFromCache(this);
|
||||||
peak = -1;
|
peak = -1;
|
||||||
reloadTree();
|
reloadTree();
|
||||||
}
|
}
|
||||||
gain = g;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getGain() {
|
public double getGain() {
|
||||||
@@ -894,8 +942,8 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
if (d > 1d) d = 1d;
|
if (d > 1d) d = 1d;
|
||||||
if (d < low) d = low;
|
if (d < low) d = low;
|
||||||
if (d > high) d = high;
|
if (d > high) d = high;
|
||||||
peak = -1;
|
|
||||||
setGain(d);
|
setGain(d);
|
||||||
|
peak = -1;
|
||||||
getPeak();
|
getPeak();
|
||||||
reloadTree();
|
reloadTree();
|
||||||
return d;
|
return d;
|
||||||
@@ -945,7 +993,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
CacheManager.removeFromCache(Sentence.this);
|
CacheManager.removeFromCache(Sentence.this);
|
||||||
AudiobookRecorder.window.updateWaveform();
|
AudiobookRecorder.window.updateWaveform(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1039,7 +1087,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CacheManager.removeFromCache(Sentence.this);
|
CacheManager.removeFromCache(Sentence.this);
|
||||||
AudiobookRecorder.window.updateWaveform();
|
AudiobookRecorder.window.updateWaveform(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1084,7 +1132,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CacheManager.removeFromCache(this);
|
CacheManager.removeFromCache(this);
|
||||||
AudiobookRecorder.window.updateWaveform();
|
AudiobookRecorder.window.updateWaveform(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double[][] getDoubleDataS16LE(AudioInputStream s, AudioFormat format) throws IOException {
|
public double[][] getDoubleDataS16LE(AudioInputStream s, AudioFormat format) throws IOException {
|
||||||
|
|||||||
Reference in New Issue
Block a user