Solved

ArrayIndexOutOfBoundsException

Posted on 2011-02-24
16
339 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
Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

 

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

Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
advertisement module in core php 4 162
thymeleaf natural templating vs JSP 2 99
Java Jpanels and Jframe 8 33
CSV file parsing thru Java 13 31
Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Java had always been an easily readable and understandable language.  Some relatively recent changes in the language seem to be changing this pretty fast, and anyone that had not seen any Java code for the last 5 years will possibly have issues unde…
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:

773 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