Add waveform split and cut functionality

This commit is contained in:
2019-08-14 19:58:06 +01:00
parent 02e85fb354
commit 187c3edaf6
9 changed files with 483 additions and 30 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

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

@@ -30,7 +30,7 @@ public class AudiobookRecorder extends JFrame {
// Settings - tweakable // Settings - tweakable
public static final int PLAYBACK_CHUNK_SIZE = 16384; public static final int PLAYBACK_CHUNK_SIZE = 1024;
public static final String SPHINX_MODEL = "resource:/edu/cmu/sphinx/models/en-us/en-us"; public static final String SPHINX_MODEL = "resource:/edu/cmu/sphinx/models/en-us/en-us";
@@ -103,6 +103,9 @@ public class AudiobookRecorder extends JFrame {
JButtonSpacePlay reprocessAudioFFT; JButtonSpacePlay reprocessAudioFFT;
JButtonSpacePlay reprocessAudioPeak; JButtonSpacePlay reprocessAudioPeak;
JButtonSpacePlay normalizeAudio; JButtonSpacePlay normalizeAudio;
JToggleButtonSpacePlay selectSplitMode;
JToggleButtonSpacePlay selectCutMode;
JButtonSpacePlay doCutSplit;
JComboBox<KVPair<String,String>> effectChain; JComboBox<KVPair<String,String>> effectChain;
@@ -423,6 +426,23 @@ public class AudiobookRecorder extends JFrame {
} }
}); });
selectSplitMode = new JToggleButtonSpacePlay(Icons.split, "Toggle split mode", new ActionListener() {
public void actionPerformed(ActionEvent e) {
toggleSplitMode();
}
});
selectCutMode = new JToggleButtonSpacePlay(Icons.cut, "Toggle cut mode", new ActionListener() {
public void actionPerformed(ActionEvent e) {
toggleCutMode();
}
});
doCutSplit = new JButtonSpacePlay(Icons.docut, "Perform cut or split", new ActionListener() {
public void actionPerformed(ActionEvent e) {
executeCutOrSplit();
}
});
postSentenceGap = new JSpinner(new SteppedNumericSpinnerModel(0, 5000, 100, 0)); postSentenceGap = new JSpinner(new SteppedNumericSpinnerModel(0, 5000, 100, 0));
postSentenceGap.setPreferredSize(new Dimension(50, 20)); postSentenceGap.setPreferredSize(new Dimension(50, 20));
@@ -487,6 +507,11 @@ public class AudiobookRecorder extends JFrame {
gainPercent.setEnabled(!selectedSentence.isLocked()); gainPercent.setEnabled(!selectedSentence.isLocked());
reprocessAudioFFT.setEnabled(!selectedSentence.isLocked()); reprocessAudioFFT.setEnabled(!selectedSentence.isLocked());
reprocessAudioPeak.setEnabled(!selectedSentence.isLocked()); reprocessAudioPeak.setEnabled(!selectedSentence.isLocked());
selectCutMode.setEnabled(!selectedSentence.isLocked());
selectSplitMode.setEnabled(!selectedSentence.isLocked());
doCutSplit.setEnabled(false);
selectCutMode.setSelected(false);
selectSplitMode.setSelected(false);
bookTreeModel.reload(selectedSentence); bookTreeModel.reload(selectedSentence);
} }
@@ -561,6 +586,10 @@ public class AudiobookRecorder extends JFrame {
} }
}); });
controlsBottom.add(selectSplitMode);
controlsBottom.add(selectCutMode);
controlsBottom.add(doCutSplit);
sampleControl.add(controlsTop, BorderLayout.NORTH); sampleControl.add(controlsTop, BorderLayout.NORTH);
sampleControl.add(controlsLeft, BorderLayout.WEST); sampleControl.add(controlsLeft, BorderLayout.WEST);
sampleControl.add(controlsRight, BorderLayout.EAST); sampleControl.add(controlsRight, BorderLayout.EAST);
@@ -1704,13 +1733,14 @@ public class AudiobookRecorder extends JFrame {
try { try {
fos = new FileOutputStream(config); fos = new FileOutputStream(config);
prefs.storeToXML(fos, "Audiobook Recorder Description"); prefs.storeToXML(fos, "Audiobook Recorder Description");
} catch (Exception e) { } catch (Exception ex) {
e.printStackTrace(); ex.printStackTrace();
} }
if (fos != null) { if (fos != null) {
try { try {
fos.close(); fos.close();
} catch (Exception e) { } catch (Exception ex) {
ex.printStackTrace();
} }
} }
} }
@@ -1813,6 +1843,11 @@ public class AudiobookRecorder extends JFrame {
gainPercent.setEnabled(!s.isLocked()); gainPercent.setEnabled(!s.isLocked());
reprocessAudioFFT.setEnabled(!s.isLocked()); reprocessAudioFFT.setEnabled(!s.isLocked());
reprocessAudioPeak.setEnabled(!s.isLocked()); reprocessAudioPeak.setEnabled(!s.isLocked());
selectCutMode.setEnabled(!s.isLocked());
selectSplitMode.setEnabled(!s.isLocked());
doCutSplit.setEnabled(false);
selectCutMode.setSelected(false);
selectSplitMode.setSelected(false);
} else { } else {
selectedSentence = null; selectedSentence = null;
sampleWaveform.clearData(); sampleWaveform.clearData();
@@ -1820,6 +1855,11 @@ public class AudiobookRecorder extends JFrame {
gainPercent.setValue(100); gainPercent.setValue(100);
locked.setSelected(false); locked.setSelected(false);
attention.setSelected(false); attention.setSelected(false);
selectCutMode.setEnabled(false);
selectSplitMode.setEnabled(false);
doCutSplit.setEnabled(false);
selectCutMode.setSelected(false);
selectSplitMode.setSelected(false);
} }
} }
}); });
@@ -2045,6 +2085,7 @@ public class AudiobookRecorder extends JFrame {
play = AudioSystem.getSourceDataLine(format, Options.getPlaybackMixer()); play = AudioSystem.getSourceDataLine(format, Options.getPlaybackMixer());
play.open(format); play.open(format);
play.start(); play.start();
play.drain();
bookTree.scrollPathToVisible(new TreePath(s.getPath())); bookTree.scrollPathToVisible(new TreePath(s.getPath()));
data = s.getPCMData(); data = s.getPCMData();
@@ -2068,6 +2109,7 @@ public class AudiobookRecorder extends JFrame {
play.close(); play.close();
} }
play = null; play = null;
e.printStackTrace();
} }
} }
}); });
@@ -2117,6 +2159,82 @@ public class AudiobookRecorder extends JFrame {
} }
public void playToSelectedSentence() {
if (selectedSentence == null) return;
if (playing != null) return;
if (getNoiseFloor() == 0) {
alertNoRoomNoise();
return;
}
playing = selectedSentence;
playingThread = new Thread(new Runnable() {
public void run() {
Sentence s = playing;
byte[] data;
try {
AudioFormat sampleformat = s.getAudioFormat();
AudioFormat format = new AudioFormat(sampleformat.getSampleRate(), 16, 2, true, false);
play = AudioSystem.getSourceDataLine(format, Options.getPlaybackMixer());
play.open(format);
play.start();
play.drain();
bookTree.scrollPathToVisible(new TreePath(s.getPath()));
data = s.getPCMData();
int startPos = 0;
int endPos = data.length / format.getFrameSize();
//foobar
if (selectSplitMode.isSelected()) {
endPos = sampleWaveform.getCutStart() - selectedSentence.getStartCrossing();
if (endPos < 0) endPos = 0;
} else if (selectCutMode.isSelected()) {
startPos = sampleWaveform.getCutStart() - selectedSentence.getStartCrossing();;
endPos = sampleWaveform.getCutEnd() - selectedSentence.getStartCrossing();;
if (startPos < 0) startPos = 0;
if (endPos < 0) endPos = 0;
}
startPos *= format.getFrameSize();
endPos *= format.getFrameSize();
if (startPos > data.length) startPos = data.length;
if (endPos > data.length) endPos = data.length;
for (int pos = startPos; pos < endPos; pos += PLAYBACK_CHUNK_SIZE) {
sampleWaveform.setPlayMarker(pos / format.getFrameSize());
int l = data.length - pos;
if (l > PLAYBACK_CHUNK_SIZE) l = PLAYBACK_CHUNK_SIZE;
play.write(data, pos, l);
}
play.drain();
play.stop();
play.close();
play = null;
playing = null;
} catch (Exception e) {
playing = null;
if (play != null) {
play.drain();
play.stop();
play.close();
}
play = null;
e.printStackTrace();
}
}
});
playingThread.setDaemon(true);
playingThread.start();
}
public void playFromSelectedSentence() { public void playFromSelectedSentence() {
if (selectedSentence == null) return; if (selectedSentence == null) return;
if (playing != null) return; if (playing != null) return;
@@ -2138,6 +2256,7 @@ public class AudiobookRecorder extends JFrame {
play = AudioSystem.getSourceDataLine(format, Options.getPlaybackMixer()); play = AudioSystem.getSourceDataLine(format, Options.getPlaybackMixer());
play.open(format); play.open(format);
play.start(); play.start();
play.drain();
while (playing != null) { while (playing != null) {
bookTree.scrollPathToVisible(new TreePath(s.getPath())); bookTree.scrollPathToVisible(new TreePath(s.getPath()));
@@ -2202,6 +2321,7 @@ public class AudiobookRecorder extends JFrame {
play.close(); play.close();
} }
play = null; play = null;
e.printStackTrace();
} }
} }
}); });
@@ -2409,6 +2529,7 @@ public class AudiobookRecorder extends JFrame {
try { try {
Files.copy(srcFile.toPath(), dstFile.toPath()); Files.copy(srcFile.toPath(), dstFile.toPath());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
} }
} }
@@ -2536,6 +2657,7 @@ public class AudiobookRecorder extends JFrame {
f.delete(); f.delete();
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();
} }
pd.closeDialog(); pd.closeDialog();
} }
@@ -3012,4 +3134,87 @@ public class AudiobookRecorder extends JFrame {
state = STOPPING; state = STOPPING;
} }
public void toggleSplitMode() {
selectCutMode.setSelected(false);
if (selectedSentence != null) {
sampleWaveform.setDisplaySplit(selectSplitMode.isSelected());
}
doCutSplit.setEnabled(selectSplitMode.isSelected());
toolBar.enablePlayTo(selectSplitMode.isSelected());
}
public void toggleCutMode() {
selectSplitMode.setSelected(false);
if (selectedSentence != null) {
sampleWaveform.setDisplayCut(selectCutMode.isSelected());
}
doCutSplit.setEnabled(selectCutMode.isSelected());
toolBar.enablePlayTo(selectCutMode.isSelected());
}
public void doCut(int start, int end) {
try {
double[][] samples = selectedSentence.getRawAudioData();
double[][] croppedSamples = new double[samples.length - (end - start)][2];
int a = 0;
for (int i = 0; i < samples.length; i++) {
if ((i < start) || (i > end)) {
croppedSamples[a++] = samples[i];
}
}
selectedSentence.writeAudioData(croppedSamples);
selectedSentence.autoTrimSample();
updateWaveform();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void doSplit(int at) {
try {
Sentence newSentence = selectedSentence.cloneSentence();
Chapter c = (Chapter)selectedSentence.getParent();
int idx = bookTreeModel.getIndexOfChild(c, selectedSentence);
bookTreeModel.insertNodeInto(newSentence, c, idx);
double[][] samples = selectedSentence.getRawAudioData();
double[][] startSamples = new double[at][2];
double[][] endSamples = new double[samples.length - at][2];
int a = 0;
int b = 0;
for (int i = 0; i < samples.length; i++) {
if (i < at) {
startSamples[a++] = samples[i];
} else {
endSamples[b++] = samples[i];
}
}
newSentence.writeAudioData(startSamples);
selectedSentence.writeAudioData(endSamples);
selectedSentence.autoTrimSample();
newSentence.autoTrimSample();
updateWaveform();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void executeCutOrSplit() {
int start = sampleWaveform.getCutStart();
int end = sampleWaveform.getCutEnd();
if (selectCutMode.isSelected()) {
doCut(start, end);
} else if (selectSplitMode.isSelected()) {
doSplit(start);
}
selectCutMode.setSelected(false);
selectSplitMode.setSelected(false);
toolBar.enablePlayTo(false);
doCutSplit.setEnabled(false);
}
} }

View File

@@ -33,4 +33,8 @@ public class Icons {
static public final ImageIcon dollar = new ImageIcon(Icons.class.getResource("icons/dollar.png")); 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 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 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"));
} }

View File

@@ -14,6 +14,7 @@ public class MainToolBar extends JToolBar {
JButtonSpacePlay recordRoomNoise; JButtonSpacePlay recordRoomNoise;
JButtonSpacePlay playSentence; JButtonSpacePlay playSentence;
JButtonSpacePlay playonSentence; JButtonSpacePlay playonSentence;
JButtonSpacePlay playtoSentence;
JButtonSpacePlay stopPlaying; JButtonSpacePlay stopPlaying;
JButtonSpacePlay eq; JButtonSpacePlay eq;
JToggleButton mic; JToggleButton mic;
@@ -78,6 +79,14 @@ public class MainToolBar extends JToolBar {
}); });
add(playonSentence); 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() { stopPlaying = new JButtonSpacePlay(Icons.stop, "Stop playing", new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
root.stopPlaying(); root.stopPlaying();
@@ -124,4 +133,8 @@ public class MainToolBar extends JToolBar {
setFloatable(false); setFloatable(false);
} }
public void enablePlayTo(boolean b) {
playtoSentence.setEnabled(b);
}
} }

View File

@@ -187,12 +187,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
processedAudio = null; processedAudio = null;
if (!id.equals("room-noise")) { if (!id.equals("room-noise")) {
String tm = Options.get("audio.recording.trim"); autoTrimSample(true);
if (tm.equals("peak")) {
autoTrimSamplePeak(true);
} else if (tm.equals("fft")) {
autoTrimSampleFFT(true);
}
if (Options.getBoolean("process.sphinx")) { if (Options.getBoolean("process.sphinx")) {
recognise(); recognise();
} }
@@ -200,6 +195,19 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
public void autoTrimSample() {
autoTrimSample(false);
}
public void autoTrimSample(boolean useRaw) {
String tm = Options.get("audio.recording.trim");
if (tm.equals("peak")) {
autoTrimSamplePeak(useRaw);
} else if (tm.equals("fft")) {
autoTrimSampleFFT(useRaw);
}
}
public static final int FFTBuckets = 1024; public static final int FFTBuckets = 1024;
public void autoTrimSampleFFT() { public void autoTrimSampleFFT() {
@@ -712,7 +720,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
if (g == gain) return; if (g == gain) return;
if (gain != g) { if (gain != g) {
clearCache(); CacheManager.removeFromCache(this);
} }
gain = g; gain = g;
} }
@@ -758,7 +766,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
proc.waitFor(); proc.waitFor();
} catch (Exception e) { } catch (Exception e) {
} }
clearCache(); CacheManager.removeFromCache(Sentence.this);
AudiobookRecorder.window.updateWaveform(); AudiobookRecorder.window.updateWaveform();
} }
} }
@@ -848,7 +856,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
} }
clearCache(); CacheManager.removeFromCache(Sentence.this);
AudiobookRecorder.window.updateWaveform(); AudiobookRecorder.window.updateWaveform();
} }
} }
@@ -891,7 +899,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
e.printStackTrace(); e.printStackTrace();
} }
clearCache(); CacheManager.removeFromCache(this);
AudiobookRecorder.window.updateWaveform(); AudiobookRecorder.window.updateWaveform();
} }
@@ -899,7 +907,6 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
long len = s.getFrameLength(); long len = s.getFrameLength();
int frameSize = format.getFrameSize(); int frameSize = format.getFrameSize();
int chans = format.getChannels(); int chans = format.getChannels();
int bytes = frameSize / chans;
byte[] frame = new byte[frameSize]; byte[] frame = new byte[frameSize];
double[][] samples = new double[(int)len][2]; double[][] samples = new double[(int)len][2];
@@ -916,26 +923,163 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
int right = (rh << 8) | rl; int right = (rh << 8) | rl;
if ((left & 0x8000) == 0x8000) left |= 0xFFFF0000; if ((left & 0x8000) == 0x8000) left |= 0xFFFF0000;
if ((right & 0x8000) == 0x8000) right |= 0xFFFF0000; if ((right & 0x8000) == 0x8000) right |= 0xFFFF0000;
samples[(int)fno][LEFT] = (double)left / 32768d; samples[(int)fno][LEFT] = (double)left / 32767d;
samples[(int)fno][RIGHT] = (double)right / 32768d; samples[(int)fno][RIGHT] = (double)right / 32767d;
} else { } else {
int l = frame[0] >= 0 ? frame[0] : 256 + frame[0]; int l = frame[0] >= 0 ? frame[0] : 256 + frame[0];
int h = frame[1] >= 0 ? frame[1] : 256 + frame[1]; int h = frame[1] >= 0 ? frame[1] : 256 + frame[1];
int mono = (h << 8) | l; int mono = (h << 8) | l;
if ((mono & 0x8000) == 0x8000) mono |= 0xFFFF0000; if ((mono & 0x8000) == 0x8000) mono |= 0xFFFF0000;
samples[(int)fno][LEFT] = (double)mono / 32768d; samples[(int)fno][LEFT] = (double)mono / 32767d;
samples[(int)fno][RIGHT] = (double)mono / 32768d; samples[(int)fno][RIGHT] = (double)mono / 32767d;
} }
} }
return samples; return samples;
} }
public void writeDoubleDataS16LE(double[][] samples, AudioFormat format) throws IOException {
int chans = format.getChannels();
int frames = samples.length;
byte[] buffer;
if (chans == 2) {
int buflen = frames * 4;
buffer = new byte[buflen];
for (int i = 0; i < frames; i++) {
double left = samples[i][LEFT];
double right = samples[i][RIGHT];
int off = i * 4;
left *= 32767d;
right *= 32767d;
int li = (int)left;
int ri = (int)right;
if (li > 32767) li = 32767;
if (li < -32767) li = -32767;
if (ri > 32767) ri = 32767;
if (ri < -32767) ri = -32767;
buffer[off + 0] = (byte)(li & 0xFF);
buffer[off + 1] = (byte)((li >> 8) & 0xFF);
buffer[off + 2] = (byte)(ri & 0xFF);
buffer[off + 3] = (byte)((ri >> 8) & 0xFF);
}
} else {
int buflen = frames * 2;
buffer = new byte[buflen];
for (int i = 0; i < frames; i++) {
double left = samples[i][LEFT];
double right = samples[i][RIGHT];
double mono = (left + right) / 2d;
int off = i * 2;
mono *= 32767d;
int mi = (int)mono;
if (mi > 32767) mi = 32767;
if (mi < -32767) mi = -32767;
buffer[off + 0] = (byte)(mi & 0xFF);
buffer[off + 1] = (byte)((mi >> 8) & 0xFF);
}
}
backup();
ByteArrayInputStream bis = new ByteArrayInputStream(buffer);
AudioInputStream ais = new AudioInputStream(bis, format, frames);
File wavFile = getFile();
FileOutputStream fos = new FileOutputStream(wavFile);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, fos);
fos.close();
ais.close();
}
public void writeDoubleDataS24LE(double[][] samples, AudioFormat format) throws IOException {
int chans = format.getChannels();
int frames = samples.length;
byte[] buffer;
if (chans == 2) {
int buflen = frames * 6;
buffer = new byte[buflen];
for (int i = 0; i < frames; i++) {
double left = samples[i][LEFT];
double right = samples[i][RIGHT];
int off = i * 6;
left *= 8388607d;
right *= 8388607d;
int li = (int)left;
int ri = (int)right;
if (li > 8388607) li = 8388607;
if (li < -8388607) li = -8388607;
if (ri > 8388607) ri = 8388607;
if (ri < -8388607) ri = -8388607;
buffer[off + 0] = (byte)(li & 0xFF);
buffer[off + 1] = (byte)((li >> 8) & 0xFF);
buffer[off + 2] = (byte)((li >> 16) & 0xFF);
buffer[off + 3] = (byte)(ri & 0xFF);
buffer[off + 4] = (byte)((ri >> 8) & 0xFF);
buffer[off + 5] = (byte)((ri >> 16) & 0xFF);
}
} else {
int buflen = frames * 3;
buffer = new byte[buflen];
for (int i = 0; i < frames; i++) {
double left = samples[i][LEFT];
double right = samples[i][RIGHT];
double mono = (left + right) / 2d;
int off = i * 3;
mono *= 8388607d;
int mi = (int)mono;
if (mi > 8388607) mi = 8388607;
if (mi < -8388607) mi = -8388607;
buffer[off + 0] = (byte)(mi & 0xFF);
buffer[off + 1] = (byte)((mi >> 8) & 0xFF);
buffer[off + 2] = (byte)((mi >> 16) & 0xFF);
}
}
backup();
ByteArrayInputStream bis = new ByteArrayInputStream(buffer);
AudioInputStream ais = new AudioInputStream(bis, format, frames);
File wavFile = getFile();
FileOutputStream fos = new FileOutputStream(wavFile);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, fos);
fos.close();
ais.close();
}
public void writeAudioData(double[][] samples) throws IOException {
AudioFormat format = getAudioFormat();
switch (format.getSampleSizeInBits()) {
case 16:
writeDoubleDataS16LE(samples, format);
break;
case 24:
writeDoubleDataS24LE(samples, format);
break;
}
CacheManager.removeFromCache(this);
}
public double[][] getDoubleDataS24LE(AudioInputStream s, AudioFormat format) throws IOException { public double[][] getDoubleDataS24LE(AudioInputStream s, AudioFormat format) throws IOException {
long len = s.getFrameLength(); long len = s.getFrameLength();
int frameSize = format.getFrameSize(); int frameSize = format.getFrameSize();
int chans = format.getChannels(); int chans = format.getChannels();
int bytes = frameSize / chans;
byte[] frame = new byte[frameSize]; byte[] frame = new byte[frameSize];
double[][] samples = new double[(int)len][2]; double[][] samples = new double[(int)len][2];
@@ -955,16 +1099,16 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
int right = (rh << 16) | (rm << 8) | rl; int right = (rh << 16) | (rm << 8) | rl;
if ((left & 0x800000) == 0x800000) left |= 0xFF000000; if ((left & 0x800000) == 0x800000) left |= 0xFF000000;
if ((right & 0x800000) == 0x800000) right |= 0xFF000000; if ((right & 0x800000) == 0x800000) right |= 0xFF000000;
samples[(int)fno][LEFT] = (double)left / 8388608d; samples[(int)fno][LEFT] = (double)left / 8388607d;
samples[(int)fno][RIGHT] = (double)right / 8388608d; samples[(int)fno][RIGHT] = (double)right / 8388607d;
} else { } else {
int l = frame[0] >= 0 ? frame[0] : 256 + frame[0]; int l = frame[0] >= 0 ? frame[0] : 256 + frame[0];
int m = frame[1] >= 0 ? frame[1] : 256 + frame[1]; int m = frame[1] >= 0 ? frame[1] : 256 + frame[1];
int h = frame[2] >= 0 ? frame[2] : 256 + frame[2]; int h = frame[2] >= 0 ? frame[2] : 256 + frame[2];
int mono = (h << 16) | (m << 8) | l; int mono = (h << 16) | (m << 8) | l;
if ((mono & 0x800000) == 0x800000) mono |= 0xFF000000; if ((mono & 0x800000) == 0x800000) mono |= 0xFF000000;
samples[(int)fno][LEFT] = (double)mono / 8388608d; samples[(int)fno][LEFT] = (double)mono / 8388607d;
samples[(int)fno][RIGHT] = (double)mono / 8388608d; samples[(int)fno][RIGHT] = (double)mono / 8388607d;
} }
} }
@@ -1076,16 +1220,16 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
int length = croppedData.length; int length = croppedData.length;
byte[] pcmData = new byte[length * 4]; byte[] pcmData = new byte[length * 4];
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
double sd = croppedData[i][LEFT] * 32768d; double sd = croppedData[i][LEFT] * 32767d;
int si = (int)sd; int si = (int)sd;
if (si > 32767) si = 32767; if (si > 32767) si = 32767;
if (si < -32768) si = -32768; if (si < -32767) si = -32767;
pcmData[i * 4] = (byte)(si & 0xFF); pcmData[i * 4] = (byte)(si & 0xFF);
pcmData[(i * 4) + 1] = (byte)((si & 0xFF00) >> 8); pcmData[(i * 4) + 1] = (byte)((si & 0xFF00) >> 8);
sd = croppedData[i][RIGHT] * 32768d; sd = croppedData[i][RIGHT] * 32767d;
si = (int)sd; si = (int)sd;
if (si > 32767) si = 32767; if (si > 32767) si = 32767;
if (si < -32768) si = -32768; if (si < -32767) si = -32767;
pcmData[(i * 4) + 2] = (byte)(si & 0xFF); pcmData[(i * 4) + 2] = (byte)(si & 0xFF);
pcmData[(i * 4) + 3] = (byte)((si & 0xFF00) >> 8); pcmData[(i * 4) + 3] = (byte)((si & 0xFF00) >> 8);
} }
@@ -1094,7 +1238,7 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
public void setEffectChain(String key) { public void setEffectChain(String key) {
if ((effectChain != null) && (!effectChain.equals(key))) { if ((effectChain != null) && (!effectChain.equals(key))) {
clearCache(); CacheManager.removeFromCache(this);
} }
effectChain = key; effectChain = key;
} }

View File

@@ -21,6 +21,11 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
int leftAltMarker = 0; int leftAltMarker = 0;
int rightAltMarker = 0; int rightAltMarker = 0;
int cutEntry = 0;
int cutExit = 0;
boolean displayCut = false;
boolean displaySplit = false;
int dragging = 0; int dragging = 0;
int step = 1; int step = 1;
@@ -133,7 +138,7 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
g.drawLine(n, (int)(h/2 + lave), n, (int)(h/2 - 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(0, 0, (leftAltMarker - offset)/step, h);
g.fillRect((rightAltMarker - offset)/step, 0, (num - rightAltMarker) / step , h); g.fillRect((rightAltMarker - offset)/step, 0, (num - rightAltMarker) / step , h);
@@ -145,6 +150,19 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
g.drawLine((leftMarker - offset)/step, 0, (leftMarker - offset)/step, h); g.drawLine((leftMarker - offset)/step, 0, (leftMarker - offset)/step, h);
g.drawLine((rightMarker - offset)/step, 0, (rightMarker - 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)); g.setColor(new Color(0, 255, 255));
for (int i = 0; i < h; i += 2) { for (int i = 0; i < h; i += 2) {
g.drawLine((playMarker - offset) / step, i, (playMarker - offset) / step, i); g.drawLine((playMarker - offset) / step, i, (playMarker - offset) / step, i);
@@ -192,6 +210,8 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
public void setData(double[][] s) { public void setData(double[][] s) {
samples = s; samples = s;
playMarker = 0; playMarker = 0;
displayCut = false;
displaySplit = false;
repaint(); repaint();
} }
@@ -221,6 +241,19 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
dragging = 2; dragging = 2;
return; 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) { public void mouseReleased(MouseEvent e) {
@@ -251,6 +284,19 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
return; 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)); setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
@@ -270,6 +316,18 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
if (rightMarker < leftMarker) { if (rightMarker < leftMarker) {
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(); repaint();
@@ -299,4 +357,33 @@ public class Waveform extends JPanel implements MouseListener, MouseMotionListen
playMarker = leftAltMarker + m; playMarker = leftAltMarker + m;
repaint(); 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;
}
} }