Moving code out of AudiobookRecorder.java
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,39 @@
|
|||||||
package uk.co.majenko.audiobookrecorder;
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.TreeMap;
|
||||||
import javax.sound.sampled.AudioFormat;
|
import javax.sound.sampled.AudioFormat;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.tree.TreeNode;
|
||||||
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
import javax.swing.tree.DefaultTreeModel;
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.TransformerConfigurationException;
|
||||||
import javax.xml.transform.TransformerFactory;
|
import javax.xml.transform.TransformerFactory;
|
||||||
import javax.xml.transform.dom.DOMSource;
|
import javax.xml.transform.dom.DOMSource;
|
||||||
import javax.xml.transform.stream.StreamResult;
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
import javax.xml.transform.OutputKeys;
|
||||||
import org.w3c.dom.Attr;
|
import org.w3c.dom.Attr;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Text;
|
import org.w3c.dom.Text;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
public class Book extends BookTreeNode {
|
public class Book extends BookTreeNode {
|
||||||
|
|
||||||
@@ -33,20 +43,17 @@ public class Book extends BookTreeNode {
|
|||||||
String comment;
|
String comment;
|
||||||
String ACX;
|
String ACX;
|
||||||
String manuscript;
|
String manuscript;
|
||||||
|
|
||||||
String defaultEffect = "none";
|
String defaultEffect = "none";
|
||||||
|
Sentence roomNoise = null;
|
||||||
int sampleRate;
|
int sampleRate;
|
||||||
int channels;
|
int channels;
|
||||||
int resolution;
|
int resolution;
|
||||||
|
|
||||||
String notes = null;
|
String notes = null;
|
||||||
|
|
||||||
ImageIcon icon;
|
ImageIcon icon;
|
||||||
|
|
||||||
Properties prefs;
|
Properties prefs;
|
||||||
|
|
||||||
File location;
|
File location;
|
||||||
|
Random rng = new Random();
|
||||||
|
TreeMap<String, EffectGroup> effects;
|
||||||
|
|
||||||
public Book(Properties p, String bookname) {
|
public Book(Properties p, String bookname) {
|
||||||
super(bookname);
|
super(bookname);
|
||||||
@@ -63,6 +70,57 @@ public class Book extends BookTreeNode {
|
|||||||
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name); // This should be in the load routine!!!!
|
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name); // This should be in the load routine!!!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Book(File inputFile) throws SAXException, IOException, ParserConfigurationException {
|
||||||
|
Debug.trace();
|
||||||
|
Debug.d("Loading book from", inputFile.getCanonicalPath());
|
||||||
|
if (inputFile.getName().endsWith(".abx")) {
|
||||||
|
location = inputFile.getParentFile();
|
||||||
|
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||||
|
Document doc = dBuilder.parse(inputFile);
|
||||||
|
doc.getDocumentElement().normalize();
|
||||||
|
Element root = doc.getDocumentElement();
|
||||||
|
|
||||||
|
name = getTextNode(root, "title");
|
||||||
|
author = getTextNode(root, "author");
|
||||||
|
genre = getTextNode(root, "genre");
|
||||||
|
comment = getTextNode(root, "comment");
|
||||||
|
ACX = getTextNode(root, "acx");
|
||||||
|
manuscript = getTextNode(root, "manuscript");
|
||||||
|
notes = getTextNode(root, "notes");
|
||||||
|
|
||||||
|
Element settings = getNode(root, "settings");
|
||||||
|
Element audioSettings = getNode(settings, "audio");
|
||||||
|
Element effectSettings = getNode(settings, "effects");
|
||||||
|
|
||||||
|
sampleRate = Utils.s2i(getTextNode(audioSettings, "samplerate"));
|
||||||
|
channels = Utils.s2i(getTextNode(audioSettings, "channels"));
|
||||||
|
resolution = Utils.s2i(getTextNode(audioSettings, "resolution"));
|
||||||
|
|
||||||
|
defaultEffect = getTextNode(settings, "default");
|
||||||
|
|
||||||
|
AudiobookRecorder.window.setTitle("AudioBook Recorder :: " + name); // This should be in the load routine!!!!
|
||||||
|
|
||||||
|
loadEffects();
|
||||||
|
|
||||||
|
Element chapters = getNode(root, "chapters");
|
||||||
|
|
||||||
|
NodeList chapterList = chapters.getElementsByTagName("chapter");
|
||||||
|
|
||||||
|
roomNoise = new Sentence("room-noise", "Room Noise");
|
||||||
|
roomNoise.setParentBook(this);
|
||||||
|
|
||||||
|
for (int i = 0; i < chapterList.getLength(); i++) {
|
||||||
|
Element chapterElement = (Element)chapterList.item(i);
|
||||||
|
Chapter newChapter = new Chapter(chapterElement);
|
||||||
|
newChapter.setParentBook(this);
|
||||||
|
add(newChapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
AudiobookRecorder.window.updateEffectChains(effects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void loadBookXML(Element root, DefaultTreeModel model) {
|
public void loadBookXML(Element root, DefaultTreeModel model) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
name = getTextNode(root, "title");
|
name = getTextNode(root, "title");
|
||||||
@@ -71,8 +129,6 @@ public class Book extends BookTreeNode {
|
|||||||
comment = getTextNode(root, "comment");
|
comment = getTextNode(root, "comment");
|
||||||
ACX = getTextNode(root, "acx");
|
ACX = getTextNode(root, "acx");
|
||||||
manuscript = getTextNode(root, "manuscript");
|
manuscript = getTextNode(root, "manuscript");
|
||||||
|
|
||||||
AudiobookRecorder.window.setBookNotes(getTextNode(root, "notes"));
|
|
||||||
notes = getTextNode(root, "notes");
|
notes = getTextNode(root, "notes");
|
||||||
|
|
||||||
Element settings = getNode(root, "settings");
|
Element settings = getNode(root, "settings");
|
||||||
@@ -91,6 +147,9 @@ public class Book extends BookTreeNode {
|
|||||||
|
|
||||||
NodeList chapterList = chapters.getElementsByTagName("chapter");
|
NodeList chapterList = chapters.getElementsByTagName("chapter");
|
||||||
|
|
||||||
|
roomNoise = new Sentence("room-noise", "Room Noise");
|
||||||
|
roomNoise.setParentBook(this);
|
||||||
|
|
||||||
for (int i = 0; i < chapterList.getLength(); i++) {
|
for (int i = 0; i < chapterList.getLength(); i++) {
|
||||||
Element chapterElement = (Element)chapterList.item(i);
|
Element chapterElement = (Element)chapterList.item(i);
|
||||||
Chapter newChapter = new Chapter(chapterElement, model);
|
Chapter newChapter = new Chapter(chapterElement, model);
|
||||||
@@ -155,8 +214,16 @@ public class Book extends BookTreeNode {
|
|||||||
|
|
||||||
public Chapter getLastChapter() {
|
public Chapter getLastChapter() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
|
DefaultMutableTreeNode leaf = getLastLeaf();
|
||||||
|
if (leaf instanceof Sentence) {
|
||||||
|
Sentence s = (Sentence)leaf;
|
||||||
|
return (Chapter)s.getParent();
|
||||||
|
}
|
||||||
|
if (leaf instanceof Chapter) {
|
||||||
return (Chapter)getLastLeaf();
|
return (Chapter)getLastLeaf();
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public Chapter getChapter(int n) {
|
public Chapter getChapter(int n) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
@@ -194,14 +261,9 @@ public class Book extends BookTreeNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getBookPath() {
|
|
||||||
Debug.trace();
|
|
||||||
return new File(Options.get("path.storage"), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void renameBook(String newName) {
|
public void renameBook(String newName) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
File oldDir = getBookPath();
|
File oldDir = location;
|
||||||
File newDir = new File(Options.get("path.storage"), newName);
|
File newDir = new File(Options.get("path.storage"), newName);
|
||||||
|
|
||||||
if (newDir.exists()) {
|
if (newDir.exists()) {
|
||||||
@@ -327,8 +389,7 @@ public class Book extends BookTreeNode {
|
|||||||
root.appendChild(makeTextNode(doc, "genre", genre));
|
root.appendChild(makeTextNode(doc, "genre", genre));
|
||||||
root.appendChild(makeTextNode(doc, "acx", ACX));
|
root.appendChild(makeTextNode(doc, "acx", ACX));
|
||||||
root.appendChild(makeTextNode(doc, "manuscript", manuscript));
|
root.appendChild(makeTextNode(doc, "manuscript", manuscript));
|
||||||
|
root.appendChild(makeTextNode(doc, "notes", notes));
|
||||||
root.appendChild(makeTextNode(doc, "notes", AudiobookRecorder.window.getBookNotes()));
|
|
||||||
|
|
||||||
Element settingsNode = doc.createElement("settings");
|
Element settingsNode = doc.createElement("settings");
|
||||||
root.appendChild(settingsNode);
|
root.appendChild(settingsNode);
|
||||||
@@ -405,7 +466,7 @@ public class Book extends BookTreeNode {
|
|||||||
public void setManuscript(File f) {
|
public void setManuscript(File f) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
manuscript = f.getName();
|
manuscript = f.getName();
|
||||||
File dst = new File(getBookPath(), manuscript);
|
File dst = new File(location, manuscript);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.copy(f.toPath(), dst.toPath());
|
Files.copy(f.toPath(), dst.toPath());
|
||||||
@@ -418,7 +479,7 @@ public class Book extends BookTreeNode {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (manuscript == null) return null;
|
if (manuscript == null) return null;
|
||||||
if (manuscript.equals("")) return null;
|
if (manuscript.equals("")) return null;
|
||||||
File f = new File(getBookPath(), manuscript);
|
File f = new File(location, manuscript);
|
||||||
if (f.exists()) {
|
if (f.exists()) {
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@@ -426,21 +487,34 @@ public class Book extends BookTreeNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onSelect() {
|
public void onSelect() {
|
||||||
|
Debug.trace();
|
||||||
|
AudiobookRecorder.window.setBookNotes(notes);
|
||||||
|
AudiobookRecorder.window.noiseFloorLabel.setNoiseFloor(getNoiseFloorDB());
|
||||||
|
// AudiobookRecorder.window.updateEffectChains(effects);
|
||||||
|
TreeNode p = getParent();
|
||||||
|
if (p instanceof BookTreeNode) {
|
||||||
|
BookTreeNode btn = (BookTreeNode)p;
|
||||||
|
btn.onSelect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNotes() {
|
public String getNotes() {
|
||||||
|
Debug.trace();
|
||||||
return notes;
|
return notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNotes(String n) {
|
public void setNotes(String n) {
|
||||||
|
Debug.trace();
|
||||||
notes = n;
|
notes = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getLocation() {
|
public File getLocation() {
|
||||||
|
Debug.trace();
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLocation(File l) {
|
public void setLocation(File l) {
|
||||||
|
Debug.trace();
|
||||||
location = l;
|
location = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,6 +522,7 @@ public class Book extends BookTreeNode {
|
|||||||
Debug.trace();
|
Debug.trace();
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
Debug.trace();
|
||||||
if (AudiobookRecorder.window == null) return;
|
if (AudiobookRecorder.window == null) return;
|
||||||
if (AudiobookRecorder.window.bookTreeModel == null) return;
|
if (AudiobookRecorder.window.bookTreeModel == null) return;
|
||||||
try {
|
try {
|
||||||
@@ -457,4 +532,135 @@ public class Book extends BookTreeNode {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Book getBook() {
|
||||||
|
Debug.trace();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getRoomNoise(int ms) {
|
||||||
|
Debug.trace();
|
||||||
|
|
||||||
|
if (roomNoise == null) return null;
|
||||||
|
|
||||||
|
// roomNoise.setEffectChain(getDefaultEffect());
|
||||||
|
int len = roomNoise.getSampleSize();
|
||||||
|
if (len == 0) return null;
|
||||||
|
|
||||||
|
AudioFormat f = roomNoise.getAudioFormat();
|
||||||
|
|
||||||
|
float sr = f.getSampleRate();
|
||||||
|
|
||||||
|
int samples = (int)(ms * (sr / 1000f));
|
||||||
|
|
||||||
|
int start = rng.nextInt(len - samples);
|
||||||
|
int end = start + samples;
|
||||||
|
|
||||||
|
roomNoise.setStartOffset(start);
|
||||||
|
roomNoise.setEndOffset(end);
|
||||||
|
|
||||||
|
byte[] data = roomNoise.getPCMData();
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getNoiseFloor() {
|
||||||
|
Debug.trace();
|
||||||
|
if (roomNoise == null) return 0;
|
||||||
|
return roomNoise.getPeak();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNoiseFloorDB() {
|
||||||
|
Debug.trace();
|
||||||
|
if (roomNoise == null) return 0;
|
||||||
|
return roomNoise.getPeakDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Sentence getRoomNoiseSentence() {
|
||||||
|
Debug.trace();
|
||||||
|
return roomNoise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordRoomNoise() {
|
||||||
|
Debug.trace();
|
||||||
|
if (roomNoise.startRecording()) {
|
||||||
|
|
||||||
|
java.util.Timer ticker = new java.util.Timer(true);
|
||||||
|
ticker.schedule(new TimerTask() {
|
||||||
|
public void run() {
|
||||||
|
Debug.trace();
|
||||||
|
roomNoise.stopRecording();
|
||||||
|
}
|
||||||
|
}, 5000); // 5 seconds of recording
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadEffects() {
|
||||||
|
Debug.trace();
|
||||||
|
effects = new TreeMap<String,EffectGroup>();
|
||||||
|
loadEffectsFromFolder(new File(Options.get("path.storage"), "System"));
|
||||||
|
if (getBook() != null) {
|
||||||
|
loadEffectsFromFolder(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadEffectsFromFolder(File dir) {
|
||||||
|
Debug.trace();
|
||||||
|
if (dir == null) return;
|
||||||
|
if (!dir.exists()) return;
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
for (File f : files) {
|
||||||
|
if (f.getName().endsWith(".eff")) {
|
||||||
|
EffectGroup g = loadEffect(f);
|
||||||
|
if (g != null) {
|
||||||
|
String fn = f.getName().replace(".eff","");
|
||||||
|
effects.put(fn, g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public EffectGroup loadEffect(File xml) {
|
||||||
|
Debug.trace();
|
||||||
|
try {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
Document document = builder.parse(xml);
|
||||||
|
|
||||||
|
Element root = document.getDocumentElement();
|
||||||
|
if (root.getTagName().equals("effect")) {
|
||||||
|
EffectGroup g = EffectGroup.loadEffectGroup(root);
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void save() throws ParserConfigurationException, TransformerConfigurationException, TransformerException {
|
||||||
|
Debug.trace();
|
||||||
|
if (location == null) {
|
||||||
|
location = new File(Options.get("path.storage"), getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!location.exists()) {
|
||||||
|
location.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File xml = new File(location, "audiobook.abx");
|
||||||
|
Document doc = buildDocument();
|
||||||
|
|
||||||
|
|
||||||
|
// write the content into xml file
|
||||||
|
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||||
|
Transformer transformer = transformerFactory.newTransformer();
|
||||||
|
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||||
|
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||||
|
DOMSource source = new DOMSource(doc);
|
||||||
|
StreamResult result = new StreamResult(xml);
|
||||||
|
transformer.transform(source, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,5 +16,6 @@ public abstract class BookTreeNode extends DefaultMutableTreeNode {
|
|||||||
public abstract String getNotes();
|
public abstract String getNotes();
|
||||||
|
|
||||||
public abstract void onSelect();
|
public abstract void onSelect();
|
||||||
|
public abstract Book getBook();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public class BookTreeRenderer extends DefaultTreeCellRenderer {
|
|||||||
|
|
||||||
String effectChain = s.getEffectChain();
|
String effectChain = s.getEffectChain();
|
||||||
if ((effectChain != null) && (!effectChain.equals("none"))) {
|
if ((effectChain != null) && (!effectChain.equals("none"))) {
|
||||||
Effect e = AudiobookRecorder.window.effects.get(effectChain);
|
Effect e = AudiobookRecorder.window.getBook().effects.get(effectChain);
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
JLabel eff = new JLabel(e.toString() + " ");
|
JLabel eff = new JLabel(e.toString() + " ");
|
||||||
ctx.weightx = 0.0d;
|
ctx.weightx = 0.0d;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class Chain implements Effect {
|
|||||||
|
|
||||||
public void process(double[][] samples) {
|
public void process(double[][] samples) {
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
Effect t = AudiobookRecorder.window.effects.get(target);
|
Effect t = AudiobookRecorder.window.getBook().effects.get(target);
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
t.process(samples);
|
t.process(samples);
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ public class Chain implements Effect {
|
|||||||
|
|
||||||
public void init(double sf) {
|
public void init(double sf) {
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
Effect t = AudiobookRecorder.window.effects.get(target);
|
Effect t = AudiobookRecorder.window.getBook().effects.get(target);
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
t.init(sf);
|
t.init(sf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import javax.swing.tree.DefaultTreeModel;
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
import javax.swing.tree.DefaultMutableTreeNode;
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
|
import javax.swing.tree.TreeNode;
|
||||||
|
|
||||||
import it.sauronsoftware.jave.FFMPEGLocator;
|
import it.sauronsoftware.jave.FFMPEGLocator;
|
||||||
import it.sauronsoftware.jave.AudioAttributes;
|
import it.sauronsoftware.jave.AudioAttributes;
|
||||||
@@ -52,6 +53,7 @@ public class Chapter extends BookTreeNode {
|
|||||||
int postGap;
|
int postGap;
|
||||||
|
|
||||||
String notes;
|
String notes;
|
||||||
|
Book parentBook = null;
|
||||||
|
|
||||||
public Chapter(String i, String chaptername) {
|
public Chapter(String i, String chaptername) {
|
||||||
super(chaptername);
|
super(chaptername);
|
||||||
@@ -81,6 +83,25 @@ public class Chapter extends BookTreeNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Chapter(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
name = Book.getTextNode(root, "name");
|
||||||
|
id = root.getAttribute("id");
|
||||||
|
preGap = Utils.s2i(Book.getTextNode(root, "pre-gap"));
|
||||||
|
postGap = Utils.s2i(Book.getTextNode(root, "post-gap"));
|
||||||
|
|
||||||
|
notes = Book.getTextNode(root, "notes");
|
||||||
|
|
||||||
|
Element sentencesNode = Book.getNode(root, "sentences");
|
||||||
|
NodeList sentences = sentencesNode.getElementsByTagName("sentence");
|
||||||
|
|
||||||
|
for (int i = 0; i < sentences.getLength(); i++) {
|
||||||
|
Element sentenceElement = (Element)sentences.item(i);
|
||||||
|
Sentence newSentence = new Sentence(sentenceElement);
|
||||||
|
add(newSentence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
return id;
|
return id;
|
||||||
@@ -149,7 +170,7 @@ public class Chapter extends BookTreeNode {
|
|||||||
|
|
||||||
if (getChildCount() == 0) return;
|
if (getChildCount() == 0) return;
|
||||||
|
|
||||||
Book book = AudiobookRecorder.window.book;
|
Book book = getBook();
|
||||||
|
|
||||||
File bookRoot = new File(Options.get("path.storage"), book.getName());
|
File bookRoot = new File(Options.get("path.storage"), book.getName());
|
||||||
if (!bookRoot.exists()) {
|
if (!bookRoot.exists()) {
|
||||||
@@ -183,7 +204,7 @@ public class Chapter extends BookTreeNode {
|
|||||||
attributes.setAudioAttributes(audioAttributes);
|
attributes.setAudioAttributes(audioAttributes);
|
||||||
|
|
||||||
|
|
||||||
AudioFormat sampleformat = AudiobookRecorder.window.roomNoise.getAudioFormat();
|
AudioFormat sampleformat = getBook().getRoomNoiseSentence().getAudioFormat();
|
||||||
AudioFormat format = new AudioFormat(sampleformat.getSampleRate(), 16, 2, true, false);
|
AudioFormat format = new AudioFormat(sampleformat.getSampleRate(), 16, 2, true, false);
|
||||||
byte[] data;
|
byte[] data;
|
||||||
|
|
||||||
@@ -201,7 +222,7 @@ public class Chapter extends BookTreeNode {
|
|||||||
File taggedFile = new File(export, book.getName() + " - " + name + ".mp3");
|
File taggedFile = new File(export, book.getName() + " - " + name + ".mp3");
|
||||||
|
|
||||||
FileOutputStream fos = new FileOutputStream(exportFile);
|
FileOutputStream fos = new FileOutputStream(exportFile);
|
||||||
data = AudiobookRecorder.window.getRoomNoise(Utils.s2i(Options.get("catenation.pre-chapter")));
|
data = getBook().getRoomNoise(Utils.s2i(Options.get("catenation.pre-chapter")));
|
||||||
fullLength += data.length;
|
fullLength += data.length;
|
||||||
fos.write(data);
|
fos.write(data);
|
||||||
|
|
||||||
@@ -218,9 +239,9 @@ public class Chapter extends BookTreeNode {
|
|||||||
fos.write(data);
|
fos.write(data);
|
||||||
|
|
||||||
if (s.hasMoreElements()) {
|
if (s.hasMoreElements()) {
|
||||||
data = AudiobookRecorder.window.getRoomNoise(snt.getPostGap());
|
data = getBook().getRoomNoise(snt.getPostGap());
|
||||||
} else {
|
} else {
|
||||||
data = AudiobookRecorder.window.getRoomNoise(Utils.s2i(Options.get("catenation.post-chapter")));
|
data = getBook().getRoomNoise(Utils.s2i(Options.get("catenation.post-chapter")));
|
||||||
}
|
}
|
||||||
fullLength += data.length;
|
fullLength += data.length;
|
||||||
fos.write(data);
|
fos.write(data);
|
||||||
@@ -351,6 +372,11 @@ public class Chapter extends BookTreeNode {
|
|||||||
public void onSelect() {
|
public void onSelect() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
AudiobookRecorder.window.setChapterNotes(notes);
|
AudiobookRecorder.window.setChapterNotes(notes);
|
||||||
|
TreeNode p = getParent();
|
||||||
|
if (p instanceof BookTreeNode) {
|
||||||
|
BookTreeNode btn = (BookTreeNode)p;
|
||||||
|
btn.onSelect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getLength() {
|
public double getLength() {
|
||||||
@@ -366,4 +392,21 @@ public class Chapter extends BookTreeNode {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Book getBook() {
|
||||||
|
if (parentBook != null) return parentBook;
|
||||||
|
if (getParent() == null) return null;
|
||||||
|
return (Book)getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentBook(Book me) {
|
||||||
|
parentBook = me;
|
||||||
|
for (Enumeration o = children(); o.hasMoreElements();) {
|
||||||
|
Object ob = (Object)o.nextElement();
|
||||||
|
if (ob instanceof Sentence) {
|
||||||
|
Sentence s = (Sentence)ob;
|
||||||
|
s.setParentBook(me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package uk.co.majenko.audiobookrecorder;
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
|
||||||
public class EffectGroup implements Effect {
|
public class EffectGroup implements Effect {
|
||||||
String name;
|
String name;
|
||||||
@@ -66,4 +70,259 @@ public class EffectGroup implements Effect {
|
|||||||
e.init(sf);
|
e.init(sf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static EffectGroup loadEffectGroup(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
EffectGroup group = new EffectGroup(root.getAttribute("name"));
|
||||||
|
NodeList kids = root.getChildNodes();
|
||||||
|
for (int i = 0; i < kids.getLength(); i++) {
|
||||||
|
Node kid = kids.item(i);
|
||||||
|
if (kid instanceof Element) {
|
||||||
|
Element e = (Element)kid;
|
||||||
|
if (e.getTagName().equals("biquad")) {
|
||||||
|
Effect eff = (Effect)loadBiquad(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (e.getTagName().equals("delayline")) {
|
||||||
|
Effect eff = (Effect)loadDelayLine(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (e.getTagName().equals("pan")) {
|
||||||
|
Effect eff = (Effect)loadPan(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (e.getTagName().equals("amplifier")) {
|
||||||
|
Effect eff = (Effect)loadAmplifier(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (e.getTagName().equals("chain")) {
|
||||||
|
Effect eff = (Effect)loadChain(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (e.getTagName().equals("group")) {
|
||||||
|
Effect eff = (Effect)loadEffectGroup(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (e.getTagName().equals("lfo")) {
|
||||||
|
Effect eff = (Effect)loadLFO(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (e.getTagName().equals("agc")) {
|
||||||
|
Effect eff = (Effect)loadAGC(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (e.getTagName().equals("clipping")) {
|
||||||
|
Effect eff = (Effect)loadClipping(e);
|
||||||
|
if (eff != null) {
|
||||||
|
group.addEffect(eff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Biquad loadBiquad(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
String type = root.getAttribute("type").toLowerCase();
|
||||||
|
Biquad bq = new Biquad();
|
||||||
|
|
||||||
|
if (type.equals("lowpass")) {
|
||||||
|
bq.setType(Biquad.Lowpass);
|
||||||
|
} else if (type.equals("highpass")) {
|
||||||
|
bq.setType(Biquad.Highpass);
|
||||||
|
} else if (type.equals("bandpass")) {
|
||||||
|
bq.setType(Biquad.Bandpass);
|
||||||
|
} else if (type.equals("notch")) {
|
||||||
|
bq.setType(Biquad.Notch);
|
||||||
|
} else if (type.equals("peak")) {
|
||||||
|
bq.setType(Biquad.Peak);
|
||||||
|
} else if (type.equals("lowshelf")) {
|
||||||
|
bq.setType(Biquad.Lowshelf);
|
||||||
|
} else if (type.equals("highshelf")) {
|
||||||
|
bq.setType(Biquad.Highshelf);
|
||||||
|
} else {
|
||||||
|
Debug.d("Bad Biquad type:", type);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bq.setQ(Utils.s2d(root.getAttribute("q")));
|
||||||
|
bq.setFc(Utils.s2d(root.getAttribute("fc")));
|
||||||
|
bq.setPeakGain(Utils.s2d(root.getAttribute("gain")));
|
||||||
|
return bq;
|
||||||
|
}
|
||||||
|
public static DelayLine loadDelayLine(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
DelayLine line = new DelayLine();
|
||||||
|
|
||||||
|
NodeList list = root.getChildNodes();
|
||||||
|
if (Utils.s2b(root.getAttribute("wetonly"))) {
|
||||||
|
line.setWetOnly(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < list.getLength(); i++) {
|
||||||
|
Node n = list.item(i);
|
||||||
|
if (n instanceof Element) {
|
||||||
|
Element e = (Element)n;
|
||||||
|
if (e.getTagName().equals("delay")) {
|
||||||
|
int samples = Utils.s2i(e.getAttribute("samples"));
|
||||||
|
double gain = Utils.s2d(e.getAttribute("gain"));
|
||||||
|
double pan = Utils.s2d(e.getAttribute("pan"));
|
||||||
|
DelayLineStore store = line.addDelayLine(samples, gain, pan);
|
||||||
|
|
||||||
|
|
||||||
|
NodeList inner = e.getChildNodes();
|
||||||
|
for (int j = 0; j < inner.getLength(); j++) {
|
||||||
|
Node in = inner.item(j);
|
||||||
|
if (in instanceof Element) {
|
||||||
|
Element ie = (Element)in;
|
||||||
|
|
||||||
|
if (ie.getTagName().equals("biquad")) {
|
||||||
|
Effect eff = (Effect)loadBiquad(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (ie.getTagName().equals("delayline")) {
|
||||||
|
Effect eff = (Effect)loadDelayLine(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (ie.getTagName().equals("pan")) {
|
||||||
|
Effect eff = (Effect)loadPan(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (ie.getTagName().equals("amplifier")) {
|
||||||
|
Effect eff = (Effect)loadAmplifier(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (ie.getTagName().equals("chain")) {
|
||||||
|
Effect eff = (Effect)loadChain(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (ie.getTagName().equals("group")) {
|
||||||
|
Effect eff = (Effect)loadEffectGroup(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (ie.getTagName().equals("lfo")) {
|
||||||
|
Effect eff = (Effect)loadLFO(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (ie.getTagName().equals("agc")) {
|
||||||
|
Effect eff = (Effect)loadAGC(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
} else if (ie.getTagName().equals("clipping")) {
|
||||||
|
Effect eff = (Effect)loadClipping(ie);
|
||||||
|
if (eff != null) {
|
||||||
|
store.addEffect(eff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Amplifier loadAmplifier(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
Amplifier a = new Amplifier(Utils.s2d(root.getAttribute("gain")));
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Chain loadChain(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
Chain c = new Chain(root.getAttribute("src"));
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pan loadPan(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
Pan p = new Pan(Utils.s2d(root.getAttribute("pan")));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Clipping loadClipping(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
Clipping c = new Clipping(Utils.s2d(root.getAttribute("clip")));
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LFO loadLFO(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
double f = Utils.s2d(root.getAttribute("frequency"));
|
||||||
|
double d = Utils.s2d(root.getAttribute("depth"));
|
||||||
|
double p = Utils.s2d(root.getAttribute("phase"));
|
||||||
|
double dty = Math.PI;
|
||||||
|
String waveform = root.getAttribute("waveform");
|
||||||
|
if (waveform == null) {
|
||||||
|
waveform = "sine";
|
||||||
|
}
|
||||||
|
|
||||||
|
int w = LFO.SINE;
|
||||||
|
|
||||||
|
switch (waveform.toLowerCase()) {
|
||||||
|
case "sine": w = LFO.SINE; break;
|
||||||
|
case "cosine": w = LFO.COSINE; break;
|
||||||
|
case "square": w = LFO.SQUARE; break;
|
||||||
|
case "triangle": w = LFO.TRIANGLE; break;
|
||||||
|
case "sawtooth": w = LFO.SAWTOOTH; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m = LFO.ADD;
|
||||||
|
|
||||||
|
String mode = root.getAttribute("mode");
|
||||||
|
|
||||||
|
if (mode == null) {
|
||||||
|
mode = "add";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode.toLowerCase()) {
|
||||||
|
case "add": m = LFO.ADD; break;
|
||||||
|
case "replace": m = LFO.REPLACE; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.getAttribute("duty") != null) {
|
||||||
|
int di = Utils.s2i(root.getAttribute("duty")); // 0-100;
|
||||||
|
dty = (Math.PI * 2) * ((double)di / 100d);
|
||||||
|
}
|
||||||
|
return new LFO(f, d, p, w, dty, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AGC loadAGC(Element root) {
|
||||||
|
Debug.trace();
|
||||||
|
double ceiling = Utils.s2d(root.getAttribute("ceiling"));
|
||||||
|
double limit = Utils.s2d(root.getAttribute("limit"));
|
||||||
|
double attack = Utils.s2d(root.getAttribute("attack"));
|
||||||
|
double decay = Utils.s2d(root.getAttribute("decay"));
|
||||||
|
if (ceiling < 0.0001d) {
|
||||||
|
ceiling = 0.708d; // -3dB
|
||||||
|
}
|
||||||
|
if (limit < 0.0001d) {
|
||||||
|
limit = 1d; // No gain
|
||||||
|
}
|
||||||
|
AGC agc = new AGC(ceiling, attack, decay, limit);
|
||||||
|
return agc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class MainToolBar extends JToolBar {
|
|||||||
|
|
||||||
recordRoomNoise = new JButtonSpacePlay(Icons.recordRoom, "Record Room Noise", new ActionListener() {
|
recordRoomNoise = new JButtonSpacePlay(Icons.recordRoom, "Record Room Noise", new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
root.recordRoomNoise();
|
root.book.recordRoomNoise();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
add(recordRoomNoise);
|
add(recordRoomNoise);
|
||||||
@@ -108,7 +108,7 @@ public class MainToolBar extends JToolBar {
|
|||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
JToggleButton b = (JToggleButton)e.getSource();
|
JToggleButton b = (JToggleButton)e.getSource();
|
||||||
if (b.isSelected()) {
|
if (b.isSelected()) {
|
||||||
if (!root.enableMicrophone()) {
|
if (!Microphone.start()) {
|
||||||
b.setSelected(false);
|
b.setSelected(false);
|
||||||
} else {
|
} else {
|
||||||
if (bgCol == null) {
|
if (bgCol == null) {
|
||||||
@@ -117,7 +117,7 @@ public class MainToolBar extends JToolBar {
|
|||||||
b.setBackground(Color.RED);
|
b.setBackground(Color.RED);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
root.disableMicrophone();
|
Microphone.stop();
|
||||||
if (bgCol != null) {
|
if (bgCol != null) {
|
||||||
b.setBackground(bgCol);
|
b.setBackground(bgCol);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package uk.co.majenko.audiobookrecorder;
|
||||||
|
|
||||||
|
import javax.sound.sampled.AudioFormat;
|
||||||
|
import javax.sound.sampled.AudioSystem;
|
||||||
|
import javax.sound.sampled.Mixer;
|
||||||
|
import javax.sound.sampled.SourceDataLine;
|
||||||
|
import javax.sound.sampled.TargetDataLine;
|
||||||
|
import javax.sound.sampled.AudioInputStream;
|
||||||
|
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
public class Microphone {
|
||||||
|
|
||||||
|
public static TargetDataLine device = null;
|
||||||
|
public static AudioInputStream stream = null;
|
||||||
|
|
||||||
|
public static boolean start() {
|
||||||
|
Debug.trace();
|
||||||
|
AudioFormat format = Options.getAudioFormat();
|
||||||
|
Mixer.Info mixer = Options.getRecordingMixer();
|
||||||
|
|
||||||
|
device = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
device = AudioSystem.getTargetDataLine(format, mixer);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
device = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device == null) {
|
||||||
|
JOptionPane.showMessageDialog(AudiobookRecorder.window, "Sample format not supported", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = new AudioInputStream(device);
|
||||||
|
|
||||||
|
try {
|
||||||
|
device.open();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
device = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
device.start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stop() {
|
||||||
|
Debug.trace();
|
||||||
|
try {
|
||||||
|
stream.close();
|
||||||
|
device.stop();
|
||||||
|
device.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
device = null;
|
||||||
|
stream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AudioInputStream getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TargetDataLine getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void flush() {
|
||||||
|
if (device != null) {
|
||||||
|
device.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import javax.sound.sampled.AudioSystem;
|
|||||||
import javax.sound.sampled.AudioFileFormat;
|
import javax.sound.sampled.AudioFileFormat;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.tree.TreeNode;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -88,6 +89,8 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
AudioInputStream inputStream;
|
AudioInputStream inputStream;
|
||||||
AudioFormat storedFormat = null;
|
AudioFormat storedFormat = null;
|
||||||
|
|
||||||
|
Book parentBook = null;
|
||||||
|
|
||||||
double runtime = -1d;
|
double runtime = -1d;
|
||||||
|
|
||||||
double[][] audioData = null;
|
double[][] audioData = null;
|
||||||
@@ -132,14 +135,14 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
byte[] buf = new byte[1024]; //AudiobookRecorder.window.microphone.getBufferSize()];
|
byte[] buf = new byte[1024]; //AudiobookRecorder.window.microphone.getBufferSize()];
|
||||||
FileOutputStream fos = new FileOutputStream(tempFile);
|
FileOutputStream fos = new FileOutputStream(tempFile);
|
||||||
int len = 0;
|
int len = 0;
|
||||||
AudiobookRecorder.window.microphone.flush();
|
Microphone.flush();
|
||||||
int nr = 0;
|
int nr = 0;
|
||||||
while (recording) {
|
while (recording) {
|
||||||
nr = AudiobookRecorder.window.microphoneStream.read(buf, 0, buf.length);
|
nr = Microphone.getStream().read(buf, 0, buf.length);
|
||||||
len += nr;
|
len += nr;
|
||||||
fos.write(buf, 0, nr);
|
fos.write(buf, 0, nr);
|
||||||
}
|
}
|
||||||
nr = AudiobookRecorder.window.microphoneStream.read(buf, 0, buf.length);
|
nr = Microphone.getStream().read(buf, 0, buf.length);
|
||||||
len += nr;
|
len += nr;
|
||||||
fos.write(buf, 0, nr);
|
fos.write(buf, 0, nr);
|
||||||
fos.close();
|
fos.close();
|
||||||
@@ -221,16 +224,17 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
if (text == null) text = id;
|
if (text == null) text = id;
|
||||||
if (text.equals("")) text = id;
|
if (text.equals("")) text = id;
|
||||||
|
|
||||||
if ((crossStartOffset == -1) || (crossEndOffset == -1)) {
|
// if (id.equals("room-noise")) return;
|
||||||
updateCrossings();
|
// if ((crossStartOffset == -1) || (crossEndOffset == -1)) {
|
||||||
}
|
// updateCrossings();
|
||||||
|
// }
|
||||||
|
|
||||||
if (runtime <= 0.01d) getLength();
|
// if (runtime <= 0.01d) getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean startRecording() {
|
public boolean startRecording() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
if (AudiobookRecorder.window.microphone == null) {
|
if (Microphone.getDevice() == null) {
|
||||||
JOptionPane.showMessageDialog(AudiobookRecorder.window, "Microphone not started. Start the microphone first.", "Error", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(AudiobookRecorder.window, "Microphone not started. Start the microphone first.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -242,6 +246,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
Thread rc = new Thread(recordingThread);
|
Thread rc = new Thread(recordingThread);
|
||||||
rc.setDaemon(true);
|
rc.setDaemon(true);
|
||||||
rc.start();
|
rc.start();
|
||||||
|
AudiobookRecorder.window.centralPanel.setFlash(true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -256,6 +261,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AudiobookRecorder.window.centralPanel.setFlash(false);
|
||||||
|
|
||||||
CacheManager.removeFromCache(this);
|
CacheManager.removeFromCache(this);
|
||||||
|
|
||||||
@@ -332,7 +338,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double[] roomNoiseProfile = AudiobookRecorder.window.getRoomNoiseSentence().getFFTProfile();
|
double[] roomNoiseProfile = getBook().getRoomNoiseSentence().getFFTProfile();
|
||||||
|
|
||||||
int fftSize = Options.getInteger("audio.recording.trim.blocksize");
|
int fftSize = Options.getInteger("audio.recording.trim.blocksize");
|
||||||
|
|
||||||
@@ -462,7 +468,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
double[][] samples;
|
double[][] samples;
|
||||||
samples = getProcessedAudioData();
|
samples = getProcessedAudioData();
|
||||||
if (samples == null) return;
|
if (samples == null) return;
|
||||||
double noiseFloor = AudiobookRecorder.window.getNoiseFloor();
|
double noiseFloor = getBook().getNoiseFloor();
|
||||||
noiseFloor *= 1.1;
|
noiseFloor *= 1.1;
|
||||||
|
|
||||||
// Find start
|
// Find start
|
||||||
@@ -525,7 +531,10 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
public File getFile() {
|
public File getFile() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
File b = new File(AudiobookRecorder.window.getBookFolder(), "files");
|
Debug.d("Get file for", id);
|
||||||
|
Book book = getBook();
|
||||||
|
if (book == null) return null;
|
||||||
|
File b = new File(book.getLocation(), "files");
|
||||||
if (!b.exists()) {
|
if (!b.exists()) {
|
||||||
b.mkdirs();
|
b.mkdirs();
|
||||||
}
|
}
|
||||||
@@ -534,7 +543,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
public File getTempFile() {
|
public File getTempFile() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
File b = new File(AudiobookRecorder.window.getBookFolder(), "files");
|
File b = new File(getBook().getLocation(), "files");
|
||||||
if (!b.exists()) {
|
if (!b.exists()) {
|
||||||
b.mkdirs();
|
b.mkdirs();
|
||||||
}
|
}
|
||||||
@@ -1366,6 +1375,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
synchronized public double[][] getProcessedAudioData(boolean effectsEnabled, boolean applyGain) {
|
synchronized public double[][] getProcessedAudioData(boolean effectsEnabled, boolean applyGain) {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
|
Book book = getBook();
|
||||||
loadFile();
|
loadFile();
|
||||||
if (processedAudio != null) {
|
if (processedAudio != null) {
|
||||||
return processedAudio;
|
return processedAudio;
|
||||||
@@ -1381,8 +1391,8 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
|
|
||||||
|
|
||||||
String def = AudiobookRecorder.window.getDefaultEffectsChain();
|
String def = AudiobookRecorder.window.getDefaultEffectsChain();
|
||||||
if ((def != null) && (AudiobookRecorder.window.effects != null)) {
|
if ((def != null) && (book.effects != null)) {
|
||||||
Effect eff = AudiobookRecorder.window.effects.get(def);
|
Effect eff = book.effects.get(def);
|
||||||
|
|
||||||
if (effectsEnabled) {
|
if (effectsEnabled) {
|
||||||
if (eff != null) {
|
if (eff != null) {
|
||||||
@@ -1393,7 +1403,7 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
if (effectChain != null) {
|
if (effectChain != null) {
|
||||||
// Don't double up the default chain
|
// Don't double up the default chain
|
||||||
if (!effectChain.equals(def)) {
|
if (!effectChain.equals(def)) {
|
||||||
eff = AudiobookRecorder.window.effects.get(effectChain);
|
eff = book.effects.get(effectChain);
|
||||||
if (eff != null) {
|
if (eff != null) {
|
||||||
eff.init(getAudioFormat().getFrameRate());
|
eff.init(getAudioFormat().getFrameRate());
|
||||||
eff.process(processedAudio);
|
eff.process(processedAudio);
|
||||||
@@ -1620,6 +1630,11 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
public void onSelect() {
|
public void onSelect() {
|
||||||
Debug.trace();
|
Debug.trace();
|
||||||
AudiobookRecorder.window.setSentenceNotes(notes);
|
AudiobookRecorder.window.setSentenceNotes(notes);
|
||||||
|
TreeNode p = getParent();
|
||||||
|
if (p instanceof BookTreeNode) {
|
||||||
|
BookTreeNode btn = (BookTreeNode)p;
|
||||||
|
btn.onSelect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reloadTree() {
|
void reloadTree() {
|
||||||
@@ -1692,4 +1707,21 @@ public class Sentence extends BookTreeNode implements Cacheable {
|
|||||||
reloadTree();
|
reloadTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Book getBook() {
|
||||||
|
if (parentBook != null) {
|
||||||
|
Debug.d("Returning parent book");
|
||||||
|
return parentBook; // Override for room noise which isn't attached to a book tree
|
||||||
|
}
|
||||||
|
Chapter c = (Chapter)getParent();
|
||||||
|
if (c == null) {
|
||||||
|
Debug.d("No parent found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Debug.d("Chapter: ", c.toString());
|
||||||
|
return c.getBook();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentBook(Book b) {
|
||||||
|
parentBook = b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user