0

I am working on something involves reading audio data. I need to convert the audio data byte[] to double[] (and vice versa). I need the conversion to pass the signal through a low pass filter.

For converting form bytes to doubles i use the following code snippet:

// where data is the byte array.
ByteBuffer byteBuffer = ByteBuffer.wrap(data);
// make sure that the data is in Little endian order.
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
// every double will represent 2 bytes (16bit audio sample)
// so the double[] is half length of byte[]
double[] doubleData = new double[data.length / 2];
int i = 0;
while (byteBuffer.remaining() > 2) {
    // read shorts (16bits) and cast them to doubles
    short t = byteBuffer.getShort();
    doubleData[i] = t;
    doubleData[i] /= 32768.0;
    i++;
}

I don know whether this is the best way or not especially as it give "Java out of heap space exception" with large of data bytes.

So to sum up:

  1. is there a better way to do the conversion, that doesn't consume heap space ?
  2. how convert back the doubles to bytes again ?

Any help appreciated

Thanks,

Samer Samy

Samer Makary
  • 1,815
  • 2
  • 22
  • 25

4 Answers4

1

Does it really need to be a double[] I am not a big fan of float but it will give you more than enough digits of accuracy and be half the size.

If you want to avoid using the heap use direct memory i.e. don't use a byte[], or double[] and instead using a ByteBuffer, ShortBuffer and FloatBuffer for direct memory.

BTW: setting the byte order for bytes doesn't do anything.

ByteBuffer bb = // use direct memory if possible.
ShortBuffer sb = bb.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
FloatBuffer fb = ByteBuffer.allocateDirect(sb.remaining() * 4)
                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
while(sb.remaining()>0)
    fb.put(sb.get() / 32768.0f);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
0

just a random idea on heap space: you can make the /= 32768.0 later on when you process your array

EDIT: typo in code

short[] shortData = new short[data.length / 2];
int i = 0;
while (byteBuffer.remaining() > 2) {
    // read shorts (16bits) and cast them to doubles
    short t = byteBuffer.getShort();
    shortData[i] = t;
    i++;
}
bpgergo
  • 15,669
  • 5
  • 44
  • 68
  • still how will i make it later ?! ... i will need to reserve an array of doubles with the same size, the heap problem comes from that line: double[] doubleData = new double[data.length / 2]; – Samer Makary Aug 31 '11 at 16:44
  • Sorry, I edited a typo in the code. No, you won't need to reserve an array of doubles with the same size. Later, when you process your short array, you make a double of it one by one. Anyway, Peter Lawrey's buffered tip is even better. – bpgergo Aug 31 '11 at 16:52
0

Check out HugeCollections.

The Huge collections library is designed to support large collections on data in memory efficiently without GC impact. It does this using heap less memory and generated code for efficiency.

I know it's not a full answer (you asked for any help) but for processing a big amount of data in java you will find a lot of great recipes on vanillajava blog.

Michał Šrajer
  • 30,364
  • 7
  • 62
  • 85
0

The only things you're using that use a lot of heap are "data" and especially "doubleData". So if you're looking for a way to reduce heap space, you're looking in the wrong place - you have to find a way to work without having all the doubles in memory at the same time. Or...

Do you know how to expand the Java heap size? If not, you need to learn - the default size is small - only 64MB, if memory serves (so to speak). From command line, e.g., add "-Xmx512m" for half a gig:

java -Xmx512m MyApp
Ed Staub
  • 15,480
  • 3
  • 61
  • 91