Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

ArrayIndexOutOfBoundsException

Posted on 2011-02-24
16
Medium Priority
?
347 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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 36

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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 

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 36

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 36

Assisted Solution

by:mccarl
mccarl earned 2000 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 36

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 36

Accepted Solution

by:
mccarl earned 2000 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

[Webinar] Lessons on Recovering from Petya

Skyport is working hard to help customers recover from recent attacks, like the Petya worm. This work has brought to light some important lessons. New malware attacks like this can take down your entire environment. Learn from others mistakes on how to prevent Petya like worms.

Question has a verified solution.

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

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…
In this post we will learn different types of Android Layout and some basics of an Android App.
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 the different types of variables in Java and how to declare them. Decide the type of variable desired: Put the keyword corresponding to the type of variable in front of the variable name: Use the equal sign to assign a v…
Suggested Courses

609 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