1

I am a bit confused about how to use the byte[]-buffer from Java's SourceDataLine.write()-method: In my program, I try to generate audio data which I am playing back through a SourceDataLine. However, I am generating double-values and I use 4 bytes for one sample (my AudioFormat: new AudioFormat(8000f, 32, 1, true, true)).

What is the best way to convert one double into four bytes (/ to "play" a double)?

[PS: Is a sample size of 32 bis good for normal audio playback?]

sammex
  • 93
  • 8
  • 1
    Related: http://stackoverflow.com/q/26824663/2891664. Though my answer is generally about converting bytes to samples, there is a code example which shows what you're asking. Another common way is to use `java.nio.ByteBuffer/java.nio.DoubleBuffer`. – Radiodef Apr 12 '16 at 15:45
  • 3
    32-bit sample size is about as good as it gets for audio, but 8kHz is a pretty terrible sample rate. 8kHz limits the frequency range to below 4kHz which is generally only acceptable for speech (VOIP/telephone). – Radiodef Apr 12 '16 at 15:49
  • 2
    For reference, 16-bit encoding, at 44100 fps, is commonly known as "CD Quality". With stereo, that comes to four bytes (two shorts) per frame. Having twice the bits won't compensate for such a low sample rate. (Reinforcing Radiodef's comment about quality.) – Phil Freihofner Apr 13 '16 at 02:24

1 Answers1

2

The linked answer goes into great detail about this but I'll answer your direct question. First, I'm assuming that your double values are in the range of -1.0 to 1.0. That is typically the setup. To go to 32-bit signed integers you need to scale such that 1.0 becomes 0x7fffffff and -1.0 becomes 0x80000001 which can be done by simple multiplication.

int sampleInt = sampleDouble * 0x7fffffff;

Next you need to split the ints into bytes:

byte[0] = (byte)((sampleInt >> 24) & 0xff);
byte[1] = (byte)((sampleInt >> 16) & 0xff);
byte[2] = (byte)((sampleInt >> 8)  & 0xff);
byte[3] = (byte)((sampleInt >> 0)  & 0xff);

Depending on the endianess of your output you might need to swap the order.

jaket
  • 9,140
  • 2
  • 25
  • 44
  • Why do you divide? It would be more intuitive to multiply by `Integer.MAX_VALUE` and use `AudioFormat.Encoding.PCM_Signed` for me. – sammex Apr 13 '16 at 19:08
  • 1
    Sorry that was a mistake. I'll edit the answer. You're free to use Integer.MAX_VALUE but it really depends on the final bit depth. The correct multiplier is 2^(numBits-1)-1 which in the 32-bit case happens to be Integer.MAX_VALUE. – jaket Apr 13 '16 at 19:26