Added ethereal voice effect

This commit is contained in:
2018-10-29 15:33:25 +00:00
parent f5c0d5bbfc
commit 175281537c
4 changed files with 218 additions and 4 deletions

View File

@@ -77,6 +77,7 @@ public class AudiobookRecorder extends JFrame {
JSpinner postSentenceGap; JSpinner postSentenceGap;
JCheckBox locked; JCheckBox locked;
JCheckBox attention; JCheckBox attention;
JCheckBox ethereal;
JButtonSpacePlay reprocessAudioFFT; JButtonSpacePlay reprocessAudioFFT;
JButtonSpacePlay reprocessAudioPeak; JButtonSpacePlay reprocessAudioPeak;
@@ -443,6 +444,27 @@ public class AudiobookRecorder extends JFrame {
controlsTop.add(attention); controlsTop.add(attention);
ethereal = new JCheckBox("Ethereal voice");
ethereal.setFocusable(false);
ethereal.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JCheckBox c = (JCheckBox)e.getSource();
if (c.isSelected()) {
if (selectedSentence != null) {
selectedSentence.setEthereal(true);
}
} else {
if (selectedSentence != null) {
selectedSentence.setEthereal(false);
}
}
bookTreeModel.reload(selectedSentence);
}
});
controlsTop.add(ethereal);
controlsTop.add(Box.createHorizontalGlue()); controlsTop.add(Box.createHorizontalGlue());
controlsTop.add(new JLabel("Post gap:")); controlsTop.add(new JLabel("Post gap:"));
controlsTop.add(postSentenceGap); controlsTop.add(postSentenceGap);
@@ -1015,6 +1037,7 @@ public class AudiobookRecorder extends JFrame {
JMenuItem editData = new JMenuItem("Edit Data..."); JMenuItem editData = new JMenuItem("Edit Data...");
editData.addActionListener(new ActionListener() { editData.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JTabbedPane tabs = new JTabbedPane();
BookInfoPanel info = new BookInfoPanel( BookInfoPanel info = new BookInfoPanel(
book.getName(), book.getName(),
book.getAuthor(), book.getAuthor(),
@@ -1022,7 +1045,38 @@ public class AudiobookRecorder extends JFrame {
book.getComment(), book.getComment(),
book.getACX() book.getACX()
); );
int r = JOptionPane.showConfirmDialog(AudiobookRecorder.this, info, "Edit Book", JOptionPane.OK_CANCEL_OPTION); tabs.add("Data", info);
JPanel effects = new JPanel();
effects.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
effects.add(new JLabel("Ethereal Iterations:"), c);
c.gridx = 1;
JSpinner ethIt = new JSpinner(new SteppedNumericSpinnerModel(1, 10, 1, book.getInteger("effects.ethereal.iterations")));
effects.add(ethIt, c);
c.gridx = 0;
c.gridy++;
effects.add(new JLabel("Ethereal Attenuation:"), c);
c.gridx = 1;
JSpinner ethAt = new JSpinner(new SteppedNumericSpinnerModel(0, 100, 1, book.getInteger("effects.ethereal.attenuation")));
effects.add(ethAt, c);
c.gridx = 0;
c.gridy++;
effects.add(new JLabel("Ethereal Offset:"), c);
c.gridx = 1;
JSpinner ethOf = new JSpinner(new SteppedNumericSpinnerModel(0, 2000, 10, book.getInteger("effects.ethereal.offset")));
effects.add(ethOf, c);
c.gridx = 0;
c.gridy++;
tabs.add("Effects", effects);
int r = JOptionPane.showConfirmDialog(AudiobookRecorder.this, tabs, "Edit Book", JOptionPane.OK_CANCEL_OPTION);
if (r != JOptionPane.OK_OPTION) return; if (r != JOptionPane.OK_OPTION) return;
String tit = info.getTitle(); String tit = info.getTitle();
@@ -1031,6 +1085,10 @@ public class AudiobookRecorder extends JFrame {
String com = info.getComment(); String com = info.getComment();
String acx = info.getACX(); String acx = info.getACX();
book.set("effects.ethereal.iterations", (Integer)ethIt.getValue());
book.set("effects.ethereal.attenuation", (Integer)ethAt.getValue());
book.set("effects.ethereal.offset", (Integer)ethOf.getValue());
book.setAuthor(aut); book.setAuthor(aut);
book.setGenre(gen); book.setGenre(gen);
book.setComment(com); book.setComment(com);
@@ -1297,6 +1355,9 @@ public class AudiobookRecorder extends JFrame {
File config = new File(bookRoot, "audiobook.abk"); File config = new File(bookRoot, "audiobook.abk");
Properties prefs = new Properties(); Properties prefs = new Properties();
prefs.setProperty("effects.ethereal.iterations", book.get("effects.ethereal.iterations"));
prefs.setProperty("effects.ethereal.offset", book.get("effects.ethereal.offset"));
prefs.setProperty("effects.ethereal.attenuation", book.get("effects.ethereal.attenuation"));
prefs.setProperty("book.name", book.getName()); prefs.setProperty("book.name", book.getName());
prefs.setProperty("book.author", book.getAuthor()); prefs.setProperty("book.author", book.getAuthor());
@@ -1330,6 +1391,7 @@ public class AudiobookRecorder extends JFrame {
prefs.setProperty(String.format("%s.sentence.%08d.end-offset", keybase, i), Integer.toString(snt.getEndOffset())); prefs.setProperty(String.format("%s.sentence.%08d.end-offset", keybase, i), Integer.toString(snt.getEndOffset()));
prefs.setProperty(String.format("%s.sentence.%08d.locked", keybase, i), snt.isLocked() ? "true" : "false"); prefs.setProperty(String.format("%s.sentence.%08d.locked", keybase, i), snt.isLocked() ? "true" : "false");
prefs.setProperty(String.format("%s.sentence.%08d.attention", keybase, i), snt.getAttentionFlag() ? "true" : "false"); prefs.setProperty(String.format("%s.sentence.%08d.attention", keybase, i), snt.getAttentionFlag() ? "true" : "false");
prefs.setProperty(String.format("%s.sentence.%08d.ethereal", keybase, i), snt.getEthereal() ? "true" : "false");
i++; i++;
} }
} }
@@ -1379,7 +1441,7 @@ public class AudiobookRecorder extends JFrame {
public void buildBook(Properties prefs) { public void buildBook(Properties prefs) {
book = new Book(prefs.getProperty("book.name")); book = new Book(prefs, prefs.getProperty("book.name"));
book.setAuthor(prefs.getProperty("book.author")); book.setAuthor(prefs.getProperty("book.author"));
book.setGenre(prefs.getProperty("book.genre")); book.setGenre(prefs.getProperty("book.genre"));
@@ -1439,6 +1501,7 @@ public class AudiobookRecorder extends JFrame {
postSentenceGap.setValue(s.getPostGap()); postSentenceGap.setValue(s.getPostGap());
locked.setSelected(s.isLocked()); locked.setSelected(s.isLocked());
attention.setSelected(s.getAttentionFlag()); attention.setSelected(s.getAttentionFlag());
ethereal.setSelected(s.getEthereal());
postSentenceGap.setEnabled(!s.isLocked()); postSentenceGap.setEnabled(!s.isLocked());
reprocessAudioFFT.setEnabled(!s.isLocked()); reprocessAudioFFT.setEnabled(!s.isLocked());
@@ -1449,6 +1512,7 @@ public class AudiobookRecorder extends JFrame {
postSentenceGap.setValue(0); postSentenceGap.setValue(0);
locked.setSelected(false); locked.setSelected(false);
attention.setSelected(false); attention.setSelected(false);
ethereal.setSelected(false);
} }
} }
}); });
@@ -1488,6 +1552,7 @@ public class AudiobookRecorder extends JFrame {
s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.audition.sentence.%08d.end-offset", i)))); s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.audition.sentence.%08d.end-offset", i))));
s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.audition.sentence.%08d.locked", i)))); s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.audition.sentence.%08d.locked", i))));
s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.audition.sentence.%08d.attention", i)))); s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.audition.sentence.%08d.attention", i))));
s.setEthereal(Utils.s2b(prefs.getProperty(String.format("chapter.audition.sentence.%08d.ethereal", i))));
bookTreeModel.insertNodeInto(s, c, c.getChildCount()); bookTreeModel.insertNodeInto(s, c, c.getChildCount());
} }
@@ -1507,6 +1572,7 @@ public class AudiobookRecorder extends JFrame {
s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.open.sentence.%08d.end-offset", i)))); s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.open.sentence.%08d.end-offset", i))));
s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.open.sentence.%08d.locked", i)))); s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.open.sentence.%08d.locked", i))));
s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.open.sentence.%08d.attention", i)))); s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.open.sentence.%08d.attention", i))));
s.setEthereal(Utils.s2b(prefs.getProperty(String.format("chapter.open.sentence.%08d.ethereal", i))));
bookTreeModel.insertNodeInto(s, c, c.getChildCount()); bookTreeModel.insertNodeInto(s, c, c.getChildCount());
} }
@@ -1531,7 +1597,8 @@ public class AudiobookRecorder extends JFrame {
s.setStartOffset(Utils.s2i(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.start-offset", cno, i)))); s.setStartOffset(Utils.s2i(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.start-offset", cno, i))));
s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.end-offset", cno, i)))); s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.end-offset", cno, i))));
s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.locked", cno, i)))); s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.locked", cno, i))));
s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.attention", cno, i)))); s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.attention", cno, i))));
s.setEthereal(Utils.s2b(prefs.getProperty(String.format("chapter.%04d.sentence.%08d.ethereal", cno, i))));
bookTreeModel.insertNodeInto(s, c, c.getChildCount()); bookTreeModel.insertNodeInto(s, c, c.getChildCount());
} }
} }
@@ -1552,6 +1619,7 @@ public class AudiobookRecorder extends JFrame {
s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.close.sentence.%08d.end-offset", i)))); s.setEndOffset(Utils.s2i(prefs.getProperty(String.format("chapter.close.sentence.%08d.end-offset", i))));
s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.close.sentence.%08d.locked", i)))); s.setLocked(Utils.s2b(prefs.getProperty(String.format("chapter.close.sentence.%08d.locked", i))));
s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.close.sentence.%08d.attention", i)))); s.setAttentionFlag(Utils.s2b(prefs.getProperty(String.format("chapter.close.sentence.%08d.attention", i))));
s.setEthereal(Utils.s2b(prefs.getProperty(String.format("chapter.close.sentence.%08d.ethereal", i))));
bookTreeModel.insertNodeInto(s, c, c.getChildCount()); bookTreeModel.insertNodeInto(s, c, c.getChildCount());
} }

View File

@@ -29,8 +29,12 @@ public class Book extends DefaultMutableTreeNode {
float[] eqChannels = new float[31]; float[] eqChannels = new float[31];
public Book(String bookname) { Properties prefs;
public Book(Properties p, String bookname) {
super(bookname); super(bookname);
prefs = p;
name = bookname; name = bookname;
equaliser = new Equaliser(); equaliser = new Equaliser();
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name); AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name);
@@ -164,4 +168,22 @@ public class Book extends DefaultMutableTreeNode {
public AudioFormat getAudioFormat() { public AudioFormat getAudioFormat() {
return new AudioFormat(getSampleRate(), getResolution(), getChannels(), true, false); return new AudioFormat(getSampleRate(), getResolution(), getChannels(), true, false);
} }
public String get(String key) {
if (prefs.getProperty(key) == null) { return Options.get(key); }
return prefs.getProperty(key);
}
public Integer getInteger(String key) {
if (prefs.getProperty(key) == null) { return Options.getInteger(key); }
return Utils.s2i(prefs.getProperty(key));
}
public void set(String key, String value) {
prefs.setProperty(key, value);
}
public void set(String key, Integer value) {
prefs.setProperty(key, "" + value);
}
} }

View File

@@ -34,6 +34,10 @@ public class Options extends JDialog {
JCheckBox enableParsing; JCheckBox enableParsing;
JSpinner cacheSize; JSpinner cacheSize;
JSpinner etherealIterations;
JSpinner etherealAttenuation;
JSpinner etherealOffset;
JTextField havenApiKey; JTextField havenApiKey;
Equaliser equaliser; Equaliser equaliser;
@@ -319,6 +323,26 @@ public class Options extends JDialog {
startupScript = new JTextArea(get("scripts.startup")); startupScript = new JTextArea(get("scripts.startup"));
startScript.add(startupScript, BorderLayout.CENTER); startScript.add(startupScript, BorderLayout.CENTER);
tabs.add("Startup Script", startScript); tabs.add("Startup Script", startScript);
JPanel effects = new JPanel();
effects.setLayout(new GridBagLayout());
constraint.gridx = 0;
constraint.gridy = 0;
constraint.gridwidth = 1;
constraint.gridheight = 1;
etherealOffset = addSpinner(effects, "Ethereal Voice Offset", 0, 2000, 10, getInteger("effects.ethereal.offset"), "ms");
etherealIterations = addSpinner(effects, "Ethereal Voice Iterations", 1, 10, 1, getInteger("effects.ethereal.iterations"), "");
etherealAttenuation = addSpinner(effects, "Ethereal Voice Attenuation", 0, 100, 1, getInteger("effects.ethereal.attenuation"), "%");
tabs.add("Effects", effects);
add(tabs, BorderLayout.CENTER); add(tabs, BorderLayout.CENTER);
setTitle("Options"); setTitle("Options");
@@ -525,6 +549,10 @@ public class Options extends JDialog {
defaultPrefs.put("scripts.startup", ""); defaultPrefs.put("scripts.startup", "");
defaultPrefs.put("effects.ethereal.offset", "50");
defaultPrefs.put("effects.ethereal.iterations", "3");
defaultPrefs.put("effects.ethereal.attenuation", "50");
if (prefs == null) { if (prefs == null) {
prefs = Preferences.userNodeForPackage(AudiobookRecorder.class); prefs = Preferences.userNodeForPackage(AudiobookRecorder.class);
} }
@@ -631,6 +659,10 @@ public class Options extends JDialog {
set("process.haven.apikey", havenApiKey.getText()); set("process.haven.apikey", havenApiKey.getText());
set("cache.size", cacheSize.getValue()); set("cache.size", cacheSize.getValue());
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++) { for (int i = 0; i < 31; i++) {
set("audio.eq." + i, equaliser.getChannel(i)); set("audio.eq." + i, equaliser.getChannel(i));
} }

View File

@@ -69,6 +69,8 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
RecordingThread recordingThread; RecordingThread recordingThread;
boolean effectEthereal = false;
static class RecordingThread implements Runnable { static class RecordingThread implements Runnable {
boolean running = false; boolean running = false;
@@ -595,6 +597,8 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
} }
} }
data = postProcessData(data);
return data; return data;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@@ -602,6 +606,69 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
return null; return null;
} }
byte[] postProcessData(byte[] data) {
if (effectEthereal) {
AudioFormat format = getAudioFormat();
int frameSize = format.getFrameSize();
int channels = format.getChannels();
int bytesPerChannel = frameSize / channels;
int frames = data.length / frameSize;
int byteNo = 0;
double fpms = (double)format.getFrameRate() / 1000d;
double doubleOffset = fpms * (double) AudiobookRecorder.window.book.getInteger("effects.ethereal.offset");
int offset = (int)doubleOffset;
double attenuation = 1d - ((double)AudiobookRecorder.window.book.getInteger("effects.ethereal.attenuation") / 100d);
int copies = AudiobookRecorder.window.book.getInteger("effects.ethereal.iterations");
byte[] out = new byte[data.length];
for (int i = 0; i < frames; i++) {
if (channels == 1) {
int l = data[i * frameSize] >= 0 ? data[i * frameSize] : 256 + data[i * frameSize];
int h = data[(i * frameSize) + 1] >= 0 ? data[(i * frameSize) + 1] : 256 + data[(i * frameSize) + 1];
int sample = (h << 8) | l;
if ((sample & 0x8000) == 0x8000) sample |= 0xFFFF0000;
double sampleDouble = (double)sample;
int used = 0;
for (int j = 0; j < copies; j++) {
if (i + (j * offset) < frames) {
used++;
int lx = data[(i + (j * offset)) * frameSize] >= 0 ? data[(i + (j * offset)) * frameSize] : 256 + data[(i + (j * offset)) * frameSize];
int hx = data[((i + (j * offset)) * frameSize) + 1] >= 0 ? data[((i + (j * offset)) * frameSize) + 1] : 256 + data[((i + (j * offset)) * frameSize) + 1];
int futureSample = (hx << 8) | lx;
if ((futureSample & 0x8000) == 0x8000) futureSample |= 0xFFFF0000;
double futureDouble = (double)futureSample;
for (int k = 0; k < copies; k++) {
futureDouble *= attenuation;
}
sampleDouble = mix(sampleDouble, futureDouble);
}
}
sample = (int)sampleDouble;
if (sample > 32767) sample = 32767;
if (sample < -32768) sample = -32768;
out[i * frameSize] = (byte)(sample & 0xFF);
out[(i * frameSize) + 1] = (byte)((sample & 0xFF00) >> 8);
} else {
return data;
}
}
return out;
} else {
return data;
}
}
public void recognise() { public void recognise() {
AudiobookRecorder.window.havenQueue.submit(Sentence.this); AudiobookRecorder.window.havenQueue.submit(Sentence.this);
} }
@@ -834,4 +901,29 @@ public class Sentence extends DefaultMutableTreeNode implements Cacheable {
ex.printStackTrace(); ex.printStackTrace();
} }
} }
public void setEthereal(boolean e) {
effectEthereal = e;
}
public boolean getEthereal() {
return effectEthereal;
}
public double mix(double a, double b) {
double z;
double fa, fb, fz;
fa = a + 32768d;
fb = b + 32768d;
if (fa < 32768d && fb < 32768d) {
fz = (fa * fb) / 32768d;
} else {
fz = (2d * (fa + fb)) - ((fa * fb) / 32768d) - 65536d;
}
z = fz - 32768d;
return z;
}
} }