diff --git a/src/main/java/cyder/audio/AudioIcons.java b/src/main/java/cyder/audio/AudioIcons.java index 384732aef..cfe67be65 100644 --- a/src/main/java/cyder/audio/AudioIcons.java +++ b/src/main/java/cyder/audio/AudioIcons.java @@ -7,7 +7,7 @@ import javax.swing.*; /** - * All icons from the static audio directory loaded as {@link javax.swing.ImageIcon}s. + * Common audio icons loaded in memory as {@link javax.swing.ImageIcon}s. */ public final class AudioIcons { /** diff --git a/src/main/java/cyder/audio/WaveFile.java b/src/main/java/cyder/audio/WaveFile.java index 4f361a422..3a49b8eda 100644 --- a/src/main/java/cyder/audio/WaveFile.java +++ b/src/main/java/cyder/audio/WaveFile.java @@ -6,13 +6,9 @@ import cyder.exceptions.FatalException; import cyder.exceptions.IllegalMethodException; import cyder.files.FileUtil; -import cyder.handlers.internal.ExceptionHandler; import cyder.strings.CyderStrings; -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Clip; +import javax.sound.sampled.*; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; @@ -100,6 +96,11 @@ private WaveFile() { * Constructs a new WaveFile object. * * @param file the wave file + * @throws NullPointerException if the provided file is null + * @throws IllegalArgumentException if the provided file does not exist + * or is not of the {@link Extension#WAV} extension + * @throws WaveFileException if an exception occurs when attempting to set up + * the streams related to the wave file */ public WaveFile(File file) { Preconditions.checkNotNull(file); @@ -107,60 +108,63 @@ public WaveFile(File file) { Preconditions.checkArgument(FileUtil.validateExtension(file, Extension.WAV.getExtension())); wavFile = file; - setup(); + + try { + setupStreams(); + } catch (UnsupportedAudioFileException | IOException e) { + throw new WaveFileException("Failed to setup wave file: " + e.getMessage()); + } } /** - * Performs setup for common wav file props after the object - * has been constructed and the file validated. + * Sets up the {@link AudioInputStream} and other fields related to this wav file. + * + * @throws IOException if the constructed {@link AudioInputStream} cannot be read from or closed properly + * @throws UnsupportedAudioFileException if the File does not point to valid audio file data recognized by the system */ - private void setup() { - try { - AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(wavFile); - audioFormat = audioInputStream.getFormat(); - numFrames = audioInputStream.getFrameLength(); - - sampleRate = (int) audioFormat.getSampleRate(); - sampleSize = audioFormat.getSampleSizeInBits() / BITS_PER_SAMPLE; - numChannels = audioFormat.getChannels(); + private void setupStreams() throws IOException, UnsupportedAudioFileException { + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(wavFile); + audioFormat = audioInputStream.getFormat(); + numFrames = audioInputStream.getFrameLength(); - long dataLength = numFrames * audioFormat.getSampleSizeInBits() * audioFormat.getChannels() / 8; + sampleRate = (int) audioFormat.getSampleRate(); + sampleSize = audioFormat.getSampleSizeInBits() / BITS_PER_SAMPLE; + numChannels = audioFormat.getChannels(); - data = new byte[(int) dataLength]; - int bytesRead = audioInputStream.read(data); - if (bytesRead == -1) { - throw new FatalException("Failed to read bytes from fis constructed from: " + wavFile); - } + long dataLength = numFrames * audioFormat.getSampleSizeInBits() * audioFormat.getChannels() / 8; - audioInputStream.close(); - } catch (Exception e) { - ExceptionHandler.handle(e); + data = new byte[(int) dataLength]; + int bytesRead = audioInputStream.read(data); + if (bytesRead == -1) { + throw new FatalException("Failed to read bytes from FileInputStream constructed from: " + wavFile); } + audioInputStream.close(); + try { clip = AudioSystem.getClip(); - clipStream = AudioSystem.getAudioInputStream(wavFile); clip.open(clipStream); - clip.setFramePosition(0); isPlayable = true; - } catch (Exception e) { + } catch (IOException | LineUnavailableException | UnsupportedAudioFileException e) { // non 16/8-bit audio file isPlayable = false; clip = null; - ExceptionHandler.handle(e); } } /** - * Returns the amplitude of the wav at the provided sample point. + * Returns the amplitude of the wave at the provided sample point. + *

* Note that in case of stereos, samples go one after another meaning * 0 is the first of the left channel, 1 the first of the right, 2 * the second of the left, 3 the second of the right, etc. * - * @param samplePoint the point to sample the wav at + * @param samplePoint the point to sample the wave file at * @return the amplitude at the sample point + * @throws IllegalArgumentException if the provided sample point is less than 0 or greater + * than the data's length divided by the sample size */ public int getSample(int samplePoint) { Preconditions.checkArgument(samplePoint >= 0); @@ -187,15 +191,19 @@ public boolean isPlayable() { /** * Play the clip of this wav file. + * + * @throws NullPointerException if the encapsulated clip is null */ public void play() { Preconditions.checkNotNull(clip); - clip.start(); } /** - * Stops the clip of this wav file. + * Stops the clip of this WAV file if playing. + * + * @throws NullPointerException if either the encapsulated clip or clip stream are null + * @throws IOException if an input or output error occurs when closing the clip stream */ public void stop() throws IOException { Preconditions.checkNotNull(clip); @@ -224,9 +232,9 @@ public int getSampleSize() { } /** - * Returns the duration in seconds. + * Returns the duration of this wave file in seconds. * - * @return the duration in seconds + * @return the duration of this wave file in seconds */ public int getDurationTime() { return (int) (getNumFrames() / getAudioFormat().getFrameRate()); @@ -285,7 +293,8 @@ public String toString() { + ", dataLength=" + data.length + ", isPlayable=" + isPlayable + ", audioFormat=" + audioFormat - + ", clip=" + clip + ", sampleSize=" + sampleSize + + ", clip=" + clip + + ", sampleSize=" + sampleSize + ", numFrames=" + numFrames + ", sampleRate=" + sampleRate + ", wavFile=" + wavFile diff --git a/src/main/java/cyder/audio/WaveFileException.java b/src/main/java/cyder/audio/WaveFileException.java new file mode 100644 index 000000000..28fdaf378 --- /dev/null +++ b/src/main/java/cyder/audio/WaveFileException.java @@ -0,0 +1,20 @@ +package cyder.audio; + +/** + * An exception for {@link WaveFile}s. + */ +public class WaveFileException extends RuntimeException { + /** + * Constructs a new WaveFileException using the provided error message. + */ + public WaveFileException(String errorMessage) { + super(errorMessage); + } + + /** + * Constructs a new WaveFileException from the provided exception. + */ + public WaveFileException(Exception e) { + super(e); + } +} diff --git a/src/main/java/cyder/audio/parsers/Disposition.java b/src/main/java/cyder/audio/parsers/Disposition.java index e7979fe52..99e5c64a2 100644 --- a/src/main/java/cyder/audio/parsers/Disposition.java +++ b/src/main/java/cyder/audio/parsers/Disposition.java @@ -1,8 +1,6 @@ package cyder.audio.parsers; import com.google.gson.annotations.SerializedName; -import cyder.logging.LogTag; -import cyder.logging.Logger; /** * A disposition object serializer for a {@link Stream} object. @@ -75,11 +73,9 @@ public class Disposition { private int timedThumbnails; /** - * Constructs a new disposition object. + * Constructs a new Disposition object. */ - public Disposition() { - Logger.log(LogTag.OBJECT_CREATION, this); - } + public Disposition() {} /** * Returns the default prop. diff --git a/src/main/java/cyder/audio/parsers/ShowStreamOutput.java b/src/main/java/cyder/audio/parsers/ShowStreamOutput.java index ec44751eb..35a508bec 100644 --- a/src/main/java/cyder/audio/parsers/ShowStreamOutput.java +++ b/src/main/java/cyder/audio/parsers/ShowStreamOutput.java @@ -1,8 +1,5 @@ package cyder.audio.parsers; -import cyder.logging.LogTag; -import cyder.logging.Logger; - import java.util.ArrayList; /** @@ -15,11 +12,9 @@ public class ShowStreamOutput { private ArrayList streams; /** - * Constructs a new show stream output object. + * Constructs a new ShowStreamOutput object. */ - public ShowStreamOutput() { - Logger.log(LogTag.OBJECT_CREATION, this); - } + public ShowStreamOutput() {} /** * Returns the list of streams found by the show stream output command. diff --git a/src/main/java/cyder/audio/parsers/Stream.java b/src/main/java/cyder/audio/parsers/Stream.java index 14832e8f6..abb11f878 100644 --- a/src/main/java/cyder/audio/parsers/Stream.java +++ b/src/main/java/cyder/audio/parsers/Stream.java @@ -1,8 +1,6 @@ package cyder.audio.parsers; import com.google.gson.annotations.SerializedName; -import cyder.logging.LogTag; -import cyder.logging.Logger; import java.util.Objects; @@ -126,11 +124,9 @@ public class Stream { private Tags tags; /** - * Constructs a new stream object. + * Constructs a new Stream object. */ - public Stream() { - Logger.log(LogTag.OBJECT_CREATION, this); - } + public Stream() {} /** * Returns the index of the stream. diff --git a/src/main/java/cyder/audio/parsers/Tags.java b/src/main/java/cyder/audio/parsers/Tags.java index d7f40f4ba..a9eb054db 100644 --- a/src/main/java/cyder/audio/parsers/Tags.java +++ b/src/main/java/cyder/audio/parsers/Tags.java @@ -1,8 +1,5 @@ package cyder.audio.parsers; -import cyder.logging.LogTag; -import cyder.logging.Logger; - /** * The tags object contained within a {@link Stream} object. */ @@ -13,11 +10,9 @@ public class Tags { private String encoder; /** - * Constructs a new tags object. + * Constructs a new Tags object. */ - public Tags() { - Logger.log(LogTag.OBJECT_CREATION, this); - } + public Tags() {} /** * Returns the encoder for this audio file. diff --git a/src/main/java/cyder/audio/parsers/package-info.java b/src/main/java/cyder/audio/parsers/package-info.java new file mode 100644 index 000000000..c3a366edd --- /dev/null +++ b/src/main/java/cyder/audio/parsers/package-info.java @@ -0,0 +1,4 @@ +/** + * {@link com.google.gson.Gson} parser classes used for serialization of a JSON dump for various ffprobe commands. + */ +package cyder.audio.parsers; \ No newline at end of file