Skip to content

Commit

Permalink
audio package work
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanCheshire committed Nov 10, 2023
1 parent d5fd81b commit 9e95c34
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 64 deletions.
2 changes: 1 addition & 1 deletion src/main/java/cyder/audio/AudioIcons.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/**
Expand Down
83 changes: 46 additions & 37 deletions src/main/java/cyder/audio/WaveFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -100,67 +96,75 @@ 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);
Preconditions.checkArgument(file.exists());
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.
* <p>
* 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);
Expand All @@ -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);
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/cyder/audio/WaveFileException.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
8 changes: 2 additions & 6 deletions src/main/java/cyder/audio/parsers/Disposition.java
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.
Expand Down
9 changes: 2 additions & 7 deletions src/main/java/cyder/audio/parsers/ShowStreamOutput.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package cyder.audio.parsers;

import cyder.logging.LogTag;
import cyder.logging.Logger;

import java.util.ArrayList;

/**
Expand All @@ -15,11 +12,9 @@ public class ShowStreamOutput {
private ArrayList<Stream> 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.
Expand Down
8 changes: 2 additions & 6 deletions src/main/java/cyder/audio/parsers/Stream.java
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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.
Expand Down
9 changes: 2 additions & 7 deletions src/main/java/cyder/audio/parsers/Tags.java
Original file line number Diff line number Diff line change
@@ -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.
*/
Expand All @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/cyder/audio/parsers/package-info.java
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 9e95c34

Please sign in to comment.