Solved

ArrayIndexOutOfBoundsException

Posted on 2011-02-24
16
343 Views
Last Modified: 2012-05-11
I am getting an ArrayIndexOutOfBoundsException.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 22051
        at FlashFFT.handleAudioBytes(FlashFFT.java:174)
        at FlashFFT.generateFFT(FlashFFT.java:93)
        at CommandLine.main(CommandLine.java:26)
Java Result: 1

Here is the handleAudioBytes method:
private void handleAudioBytes() {
		left = new float[sampleSize];
		right = new float[sampleSize];

		int c = (int) ((long) (framesRead * frameSize) - (long) (audioDataBuffer.length * offset));

		if (c > 0) {
			for (int a = 0; a < sampleSize; a++, c += 4) {
				if (c >= audioDataBuffer.length) {
					c = (c - audioDataBuffer.length);
					offset++;
				}
				// channelMode == CHANNEL_MODE_STEREO && sampleType ==
				// SAMPLE_TYPE_SIXTEEN_BIT
				left[a] = ((audioDataBuffer[c + 1] << 8) + audioDataBuffer[c]) / 32767.0f;
				right[a] = ((audioDataBuffer[c + 3] << 8) + audioDataBuffer[c + 2]) / 32767.0f;
			}
		}
	}

Open in new window


line 174 is right[a] = ((audioDataBuffer[c + 3] << 8) + audioDataBuffer[c + 2]) / 32767.0f;

Anybody knwos what could be wrong?
0
Comment
Question by:chudyksg
  • 6
  • 5
  • 5
16 Comments
 
LVL 47

Expert Comment

by:for_yan
ID: 34975869
well, how do you create audoDataBuffer and can it be that c+3 would be at some point > that its dimension ?
0
 
LVL 47

Expert Comment

by:for_yan
ID: 34975885
can you print out a and c right before that line:
System.out.println("a: " + a + " c: " + c + " length:  " +  audioDataBuffer.length );
0
 
LVL 35

Expert Comment

by:mccarl
ID: 34975912
I think that you are probably assuming the audioBuffer.length will always be a multiple of 4, but somehow it is not the case. It a bit hard to work out the logic, but this change should at least resolve the error. Whether it is correct for what you are trying to do, is another matter.

Change the line

 if (c >= audioDataBuffer.length) {

to

 if (c > (audioDataBuffer.length - 4)) {
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:chudyksg
ID: 34975965
for_yan: for the print out see attached file
mccarl: that didn't help errorPrintout.txt
0
 
LVL 47

Expert Comment

by:for_yan
ID: 34975979
Noit helped c = 22048, so c+3 is out ofbounds
0
 
LVL 47

Expert Comment

by:for_yan
ID: 34975993
so check it right before executing line 174  line and skip this line , or catch
this exception and ignore it - if it is only possible
0
 
LVL 35

Expert Comment

by:mccarl
ID: 34976038
Ah, yes, I see.. My suggestion should have changed the exception though from... java.lang.ArrayIndexOutOfBoundsException: 22051    to... java.lang.ArrayIndexOutOfBoundsException: -2

As I said, you are assuming that the audioBuffer's length is a multiple of 4 (but it isn't) and so trying to process the buffer's bytes in groups of 4 just isn't going to work.


For us to help you much more, you will need to provide more details.. What is the purpose of this method, what determine the length of audioBuffer, how is audioBuffer declared, where does sampleSize, frameSize and framesRead come from?
0
 

Author Comment

by:chudyksg
ID: 34976058
Well it is not actually my code. I downloaded the source code from here http://javaflash-fft.sourceforge.net/ . It looks on the web page it is working. I want to analyse the code how it is done because I have to do something similar but when I try to run from net beans I get that error. I get the error if I run it from the command line as well
0
 
LVL 47

Expert Comment

by:for_yan
ID: 34976085
Well, it looks like it happens at the last point - not knowing anything about the details,  one option is - is just say a<(samplSize-1)
within the loop - hopefully it would not spoil too much
0
 

Author Comment

by:chudyksg
ID: 34976097
Here is the whole code
public class FlashFFT {

	private float[] left;

	private float[] right;

	private int sampleSize = 2048;

	private byte[] audioDataBuffer = null;

	private KJFFT fft = new KJFFT(512);

	private float[] old_FFT = new float[512];

	private int desiredBands = 12;

	private int framesRead = 0;

	private int position = 0;

	private AudioFormat baseFormat;

	private int offset = 0;

	private int frameSize;

	private FlashFFTDataConsumer consumer;

	public FlashFFT() {
	}

	/**
	 * @param inputFile
	 * @throws IOException
	 * @throws UnsupportedAudioFileException
	 */
	public void generateFFT(File inputFile, FlashFFTDataConsumer consumer, int desiredFPS,
			int desiredBands) {
		this.consumer = consumer;
		AudioInputStream din = null;
		AudioInputStream in = null;
		FileOutputStream fos = null;
		try {
			long time = new Date().getTime();
			this.desiredBands = desiredBands;
			AudioFileFormat baseFileFormat = null;
			baseFormat = null;
			baseFileFormat = AudioSystem.getAudioFileFormat(inputFile);
			baseFormat = baseFileFormat.getFormat();
			in = AudioSystem.getAudioInputStream(inputFile);
			AudioFormat decodedFormat = new AudioFormat(
					AudioFormat.Encoding.PCM_SIGNED,
					baseFormat.getSampleRate(), 16, baseFormat.getChannels(),
					baseFormat.getChannels() * 2, baseFormat.getSampleRate(),
					false);
			din = AudioSystem.getAudioInputStream(decodedFormat, in);

			frameSize = decodedFormat.getFrameSize();
			byte[] data = new byte[4096];
			System.out.println("Input sample rate: "
					+ baseFormat.getSampleRate() + "Hz");
			audioDataBuffer = new byte[(int) baseFormat.getSampleRate() << 1];

			int nBytesRead = 0;
			float passCount = 0;
			int sampleCount = 0;
			System.out.println("Processing input at " + desiredFPS
					+ "fps... (one mark for 100 frames)");

                        while (nBytesRead != -1) {
				nBytesRead = din.read(data, 0, data.length);
				if (nBytesRead != -1) {
					framesRead += (nBytesRead / decodedFormat.getFrameSize());
					storeAudioData(data, 0, nBytesRead);
					handleAudioBytes();
					passCount += 1000 / (baseFormat.getSampleRate() / 1000);

					if (passCount >= (1000 / desiredFPS) * sampleCount) {
						computeFFT(mergeStereo(left, right));
						sampleCount++;
						if (sampleCount % 100 == 0) {
							System.out.print("#");
							if (sampleCount % 5000 == 0)
								System.out.print("\n");
						}
					}

				}
			}
			consumer.processFinished();
			long duration = new Date().getTime() - time;
			System.out.println("\nFinished!");
			System.out.println("Processed " + (int) sampleCount / desiredFPS
					+ "s of samples in " + (int) duration / 1000 + "s ("
					+ (int) (sampleCount / desiredFPS)
					/ (int) (duration / 1000) + "x real time)");
		} catch (IOException e) {
			throw new FFTException(e);
		} catch (UnsupportedAudioFileException e) {
			throw new FFTException(e);
		} finally {
			try {
				if (din != null)
					din.close();
				if (in != null)
					in.close();
				if (fos != null) {
					fos.flush();
					fos.close();
				}
			} catch (IOException e1) {
				throw new FFTException(e1);
			}

		}
	}

	private void storeAudioData(byte[] pAudioData, int pOffset, int pLength) {

		int wOverrun = 0;

		if (position + pLength > audioDataBuffer.length - 1) {
			wOverrun = (position + pLength) - audioDataBuffer.length;
			pLength = audioDataBuffer.length - position;
		}

		System.arraycopy(pAudioData, pOffset, audioDataBuffer, position,
				pLength);
		if (wOverrun > 0) {

			System.arraycopy(pAudioData, pOffset + pLength, audioDataBuffer, 0,
					wOverrun);
			position = wOverrun;

		} else {
			position += pLength;
		}

	}

	private void handleAudioBytes() {
		left = new float[sampleSize];
		right = new float[sampleSize];

		int c = (int) ((long) (framesRead * frameSize) - (long) (audioDataBuffer.length * offset));

		if (c > 0) {
			for (int a = 0; a < sampleSize; a++, c += 4) {
				if (c > (audioDataBuffer.length - 4)) {
					c = (c - audioDataBuffer.length);
					offset++;
				}
				// channelMode == CHANNEL_MODE_STEREO && sampleType ==
				// SAMPLE_TYPE_SIXTEEN_BIT
				left[a] = ((audioDataBuffer[c + 1] << 8) + audioDataBuffer[c]) / 32767.0f;
                            //    System.out.println("a: " + a + " c: " + c + " length:  " +  audioDataBuffer.length );
				right[a] = ((audioDataBuffer[c + 3] << 8) + audioDataBuffer[c + 2]) / 32767.0f;
			}
		}
	}

	private float[] mergeStereo(float[] pLeft, float[] pRight) {

		for (int a = 0; a < pLeft.length; a++) {
			pLeft[a] = (pLeft[a] + pRight[a]) / 2.0f;
		}
		return pLeft;

	}

	private void computeFFT(float[] pSample) {
		int saMultiplier = (512 / 2) / desiredBands;

		float c = 0;
		float[] wFFT = fft.calculate(pSample);

		float wSadfrr = (0.03f);
		
		float result[] = new float[desiredBands];

		for (int a = 0, bd = 0; bd < desiredBands; a += saMultiplier, bd++) {
			float wFs = 0;

			// -- Average out nearest bands.
			for (int b = 0; b < saMultiplier; b++) {
				wFs += wFFT[a + b];
			}

			// -- Log filter.
			wFs = (wFs * (float) Math.log(bd + 2));

			if (wFs > 1.0f) {
				wFs = 1.0f;
			}

			// -- Compute SA decay...
			if (wFs >= (old_FFT[a] /* - wSadfrr */)) {

				old_FFT[a] = wFs;

			} else {

				old_FFT[a] -= wSadfrr;

				if (old_FFT[a] < 0) {
					old_FFT[a] = 0;
				}

				wFs = old_FFT[a];

			}
			
			result[bd] = wFs;	
		}
		consumer.handleFFT(result);
	}

}

Open in new window

0
 

Author Comment

by:chudyksg
ID: 34976117
After adding:  if (c > (audioDataBuffer.length - 4)) {
I am getting Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at line : left[a] = ((audioDataBuffer[c + 1] << 8) + audioDataBuffer[c]) / 32767.0f;
0
 
LVL 35

Assisted Solution

by:mccarl
mccarl earned 500 total points
ID: 34976131
It is just bad code from the looks of it. I am guessing that you might be passing in a audio file that is mono?

It seems that the code around lines 51 to 55 (in the post just above) is expecting to handle audio files of either mono or stereo, as it is not hardcoding the number of channels but it is using the number of channels from baseFormat, which is the format of the input file. However, the code in handleAudioBytes and on line 95 above is making a huge assumption that the input is in stereo.

File a bug report with the code's author!
0
 

Author Comment

by:chudyksg
ID: 34976215
Well I just downloaded a stereo file and still the same problem.
0
 
LVL 35

Expert Comment

by:mccarl
ID: 34976252
Can you post the full output for that stereo file (including the extra output statement that for_yan asked to include)?
0
 

Author Comment

by:chudyksg
ID: 34976311
I forgot to change the code to the previous one. Once I have done it, it is working. Thanks for that. Any idea how to make it accept mono files?
0
 
LVL 35

Accepted Solution

by:
mccarl earned 500 total points
ID: 34976350
This might work, it is the easiest I can see to change it. Change handleAudioBytes to this...

 
private void handleAudioBytes(int numChannels) {
		left = new float[sampleSize];
		right = new float[sampleSize];

		int c = (int) ((long) (framesRead * frameSize) - (long) (audioDataBuffer.length * offset));

		if (c > 0) {
			for (int a = 0; a < sampleSize; a++, c += 4) {
				if (c >= audioDataBuffer.length) {
					c = (c - audioDataBuffer.length);
					offset++;
				}
				if(numChannels == 2)
				{
				    // channelMode == CHANNEL_MODE_STEREO && sampleType ==
				    // SAMPLE_TYPE_SIXTEEN_BIT
				    left[a] = ((audioDataBuffer[c + 1] << 8) + audioDataBuffer[c]) / 32767.0f;
				    right[a] = ((audioDataBuffer[c + 3] << 8) + audioDataBuffer[c + 2]) / 32767.0f;
				}
				if(numChannels == 1)
				{
				    // channelMode == CHANNEL_MODE_MONO && sampleType ==
				    // SAMPLE_TYPE_SIXTEEN_BIT
				    left[a] = ((audioDataBuffer[c + 1] << 8) + audioDataBuffer[c]) / 32767.0f;
				    right[a] = left[a];
				}
			}
		}
	}

Open in new window


And then change line 75 from the above to...

 
handleAudioBytes(baseFormat.getChannels());

Open in new window


Note, that this is not by any means the best way to do this change, but it should be a quick hack to get it working. To do a better job handling both mono/stereo would require more extensive work.
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
How to get all the API from website? 11 127
servlet and mdb, jms error 1 57
how to debug htl and js pages 8 54
Java class and jar 3 42
An old method to applying the Singleton pattern in your Java code is to check if a static instance, defined in the same class that needs to be instantiated once and only once, is null and then create a new instance; otherwise, the pre-existing insta…
INTRODUCTION Working with files is a moderately common task in Java.  For most projects hard coding the file names, using parameters in configuration files, or using command-line arguments is sufficient.   However, when your application has vi…
Viewers will learn about arithmetic and Boolean expressions in Java and the logical operators used to create Boolean expressions. We will cover the symbols used for arithmetic expressions and define each logical operator and how to use them in Boole…
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question