summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-05-21 16:44:17 +0200
committerSven Gothel <[email protected]>2023-05-21 16:44:17 +0200
commit742cf0cd053f968cbf291ed367d4568c12d8bde2 (patch)
tree6036ad8cdabf04ebf90988eb81a466c39d6b7d9c
parent5c33470aea6b30c81681992567d7c92e100bdab3 (diff)
AudioFormat/AudioSink: Use float in seconds for duration to avoid losing precision when dealing with stats, averages etc
-rw-r--r--src/java/com/jogamp/common/av/AudioFormat.java46
-rw-r--r--src/java/com/jogamp/common/av/AudioSink.java24
-rw-r--r--src/java/com/jogamp/common/av/TimeFrameI.java8
-rw-r--r--src/java/jogamp/common/av/JavaSoundAudioSink.java14
-rw-r--r--src/java/jogamp/common/av/NullAudioSink.java8
5 files changed, 65 insertions, 35 deletions
diff --git a/src/java/com/jogamp/common/av/AudioFormat.java b/src/java/com/jogamp/common/av/AudioFormat.java
index 870ccd2..2802f31 100644
--- a/src/java/com/jogamp/common/av/AudioFormat.java
+++ b/src/java/com/jogamp/common/av/AudioFormat.java
@@ -79,48 +79,58 @@ public class AudioFormat {
//
/**
- * Returns the byte size of the given milliseconds
+ * Returns the byte size of the given duration in seconds
* according to {@link #sampleSize}, {@link #channelCount} and {@link #sampleRate}.
+ * <pre>
+ * final float bytesPerSample = sampleSize/8;
+ * return Math.round( duration * channelCount * bytesPerSample * sampleRate );
+ * </pre>
* <p>
* Time -> Byte Count
* </p>
+ * @param duration duration in seconds
*/
- public final int getDurationsByteSize(final int millisecs) {
- final int bytesPerSample = sampleSize >>> 3; // /8
- return Math.round( millisecs * ( (float)channelCount * (float)bytesPerSample * ( sampleRate / 1000f ) ) );
+ public final int getDurationsByteSize(final float duration) {
+ final float bytesPerSample = sampleSize >>> 3; // /8
+ return Math.round( duration * channelCount * bytesPerSample * sampleRate );
}
/**
- * Returns the duration in milliseconds of the given byte count
+ * Returns the duration in seconds of the given byte count
* according to {@link #sampleSize}, {@link #channelCount} and {@link #sampleRate}.
+ * <pre>
+ * final float bytesPerSample = sampleSize/8;
+ * return byteCount / ( channelCount * bytesPerSample * sampleRate )
+ * </pre>
* <p>
* Byte Count -> Time
* </p>
+ * @param byteCount size in bytes
*/
- public final int getBytesDuration(final int byteCount) {
- final int bytesPerSample = sampleSize >>> 3; // /8
- return Math.round( byteCount / ( (float)channelCount * (float)bytesPerSample * ( sampleRate / 1000f ) ) );
+ public final float getBytesDuration(final int byteCount) {
+ final float bytesPerSample = sampleSize >>> 3; // /8
+ return byteCount / ( channelCount * bytesPerSample * sampleRate );
}
/**
- * Returns the duration in milliseconds of the given sample count per frame and channel
+ * Returns the duration in seconds of the given sample count per frame and channel
* according to the {@link #sampleRate}, i.e.
* <pre>
- * round( ( 1000f * sampleCount ) / sampleRate )
+ * (float)sampleCount / sampleRate
* </pre>
* <p>
* Sample Count -> Time
* </p>
* @param sampleCount sample count per frame and channel
*/
- public final int getSamplesDuration(final int sampleCount) {
- return Math.round( ( 1000f * sampleCount ) / sampleRate );
+ public final float getSamplesDuration(final int sampleCount) {
+ return (float)sampleCount / sampleRate;
}
/**
- * Returns the rounded frame count of the given milliseconds and frame duration.
+ * Returns the rounded frame count of the given duration and frame duration, both in seconds.
* <pre>
- * Math.max( 1, millisecs / frameDuration + 0.5f )
+ * Math.max(1, Math.round( duration / frameDuration ))
* </pre>
* <p>
* Note: <code>frameDuration</code> can be derived by <i>sample count per frame and channel</i>
@@ -129,13 +139,13 @@ public class AudioFormat {
* <p>
* Frame Time -> Frame Count
* </p>
- * @param millisecs time in milliseconds
- * @param frameDuration duration per frame in milliseconds.
+ * @param duration duration in seconds
+ * @param frameDuration duration per frame in seconds, i.e. 1/frame_rate
* @see #getSamplesDuration(int)
* @see #getBytesDuration(int)
*/
- public final int getFrameCount(final int millisecs, final int frameDuration) {
- return Math.max(1, (int) ( (float)millisecs / (float)frameDuration + 0.5f ));
+ public final int getFrameCount(final float duration, final float frameDuration) {
+ return Math.max(1, Math.round( duration / frameDuration ));
}
/**
diff --git a/src/java/com/jogamp/common/av/AudioSink.java b/src/java/com/jogamp/common/av/AudioSink.java
index 704c2a6..b4738b3 100644
--- a/src/java/com/jogamp/common/av/AudioSink.java
+++ b/src/java/com/jogamp/common/av/AudioSink.java
@@ -65,9 +65,18 @@ public interface AudioSink {
public static abstract class AudioFrame extends TimeFrameI {
protected int byteSize;
+ /**
+ * Ctor w/ zero duration, {@link #INVALID_PTS} and zero byte size
+ */
public AudioFrame() {
this.byteSize = 0;
}
+ /**
+ * Create a new instance
+ * @param pts frame pts in milliseconds
+ * @param duration frame duration in milliseconds
+ * @param byteCount size in bytes
+ */
public AudioFrame(final int pts, final int duration, final int byteCount) {
super(pts, duration);
this.byteSize=byteCount;
@@ -89,6 +98,13 @@ public interface AudioSink {
public static class AudioDataFrame extends AudioFrame {
protected final ByteBuffer data;
+ /**
+ * Create a new instance
+ * @param pts frame pts in milliseconds
+ * @param duration frame duration in milliseconds
+ * @param bytes audio data
+ * @param byteCount size in bytes
+ */
public AudioDataFrame(final int pts, final int duration, final ByteBuffer bytes, final int byteCount) {
super(pts, duration, byteCount);
if( byteCount > bytes.remaining() ) {
@@ -343,13 +359,13 @@ public interface AudioSink {
public int getQueuedByteCount();
/**
- * Returns the current queued frame time in milliseconds for playing.
+ * Returns the current queued frame time in seconds for playing.
* <p>
* {@link #init(AudioFormat, float, int, int, int)} must be called first.
* </p>
* @see #init(AudioFormat, float, int, int, int)
*/
- public int getQueuedTime();
+ public float getQueuedTime();
/**
* Returns average frame duration last assessed @ {@link #enqueueData(int, ByteBuffer, int)} when queue was full.
@@ -357,7 +373,7 @@ public interface AudioSink {
* avgFrameDuration = {@link #getQueuedTime()} / {@link #getQueuedFrameCount()}
* </pre>
*/
- public int getAvgFrameDuration();
+ public float getAvgFrameDuration();
/**
* Return the current audio presentation timestamp (PTS) in milliseconds.
@@ -381,7 +397,7 @@ public interface AudioSink {
* <p>
* {@link #init(AudioFormat, float, int, int, int)} must be called first.
* </p>
- * @param pts presentation time stamp for the newly enqueued {@link AudioFrame}
+ * @param pts presentation time stamp in milliseconds for the newly enqueued {@link AudioFrame}
* @param bytes audio data for the newly enqueued {@link AudioFrame}
* @returns the enqueued internal {@link AudioFrame}.
* @see #init(AudioFormat, float, int, int, int)
diff --git a/src/java/com/jogamp/common/av/TimeFrameI.java b/src/java/com/jogamp/common/av/TimeFrameI.java
index a528c09..400618f 100644
--- a/src/java/com/jogamp/common/av/TimeFrameI.java
+++ b/src/java/com/jogamp/common/av/TimeFrameI.java
@@ -56,10 +56,18 @@ public class TimeFrameI {
protected int pts;
protected int duration;
+ /**
+ * Ctor w/ zero duration and {@link #INVALID_PTS}.
+ */
public TimeFrameI() {
pts = INVALID_PTS;
duration = 0;
}
+ /**
+ * Create a new instance
+ * @param pts frame pts in milliseconds
+ * @param duration frame duration in milliseconds
+ */
public TimeFrameI(final int pts, final int duration) {
this.pts = pts;
this.duration = duration;
diff --git a/src/java/jogamp/common/av/JavaSoundAudioSink.java b/src/java/jogamp/common/av/JavaSoundAudioSink.java
index bdf4e22..7cd4310 100644
--- a/src/java/jogamp/common/av/JavaSoundAudioSink.java
+++ b/src/java/jogamp/common/av/JavaSoundAudioSink.java
@@ -262,7 +262,7 @@ public class JavaSoundAudioSink implements AudioSink {
written += len;
}
playImpl();
- return new AudioDataFrame(pts, chosenFormat.getBytesDuration(byteCount), byteBuffer, byteCount);
+ return new AudioDataFrame(pts, Math.round(1000f*chosenFormat.getBytesDuration(byteCount)), byteBuffer, byteCount);
}
@Override
@@ -276,17 +276,13 @@ public class JavaSoundAudioSink implements AudioSink {
}
@Override
- public int getQueuedTime() {
- return getQueuedTimeImpl( getQueuedByteCount() );
- }
- private final int getQueuedTimeImpl(final int byteCount) {
- final int bytesPerSample = chosenFormat.sampleSize >>> 3; // /8
- return byteCount / ( chosenFormat.channelCount * bytesPerSample * ( chosenFormat.sampleRate / 1000 ) );
+ public float getQueuedTime() {
+ return chosenFormat.getBytesDuration( getQueuedByteCount() );
}
@Override
- public int getAvgFrameDuration() {
- return 0;
+ public float getAvgFrameDuration() {
+ return 0f;
}
@Override
diff --git a/src/java/jogamp/common/av/NullAudioSink.java b/src/java/jogamp/common/av/NullAudioSink.java
index 58f4b0d..ca5e2f4 100644
--- a/src/java/jogamp/common/av/NullAudioSink.java
+++ b/src/java/jogamp/common/av/NullAudioSink.java
@@ -185,13 +185,13 @@ public class NullAudioSink implements AudioSink {
}
@Override
- public int getQueuedTime() {
- return 0;
+ public float getQueuedTime() {
+ return 0f;
}
@Override
- public int getAvgFrameDuration() {
- return 0;
+ public float getAvgFrameDuration() {
+ return 0f;
}
@Override