diff options
author | Sven Gothel <[email protected]> | 2023-05-21 16:44:17 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-05-21 16:44:17 +0200 |
commit | 742cf0cd053f968cbf291ed367d4568c12d8bde2 (patch) | |
tree | 6036ad8cdabf04ebf90988eb81a466c39d6b7d9c | |
parent | 5c33470aea6b30c81681992567d7c92e100bdab3 (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.java | 46 | ||||
-rw-r--r-- | src/java/com/jogamp/common/av/AudioSink.java | 24 | ||||
-rw-r--r-- | src/java/com/jogamp/common/av/TimeFrameI.java | 8 | ||||
-rw-r--r-- | src/java/jogamp/common/av/JavaSoundAudioSink.java | 14 | ||||
-rw-r--r-- | src/java/jogamp/common/av/NullAudioSink.java | 8 |
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 |