Solved

ArrayIndexOutOfBoundsException

Posted on 2011-02-24
16
338 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
 

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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

After being asked a question last year, I went into one of my moods where I did some research and code just for the fun and learning of it all.  Subsequently, from this journey, I put together this article on "Range Searching Using Visual Basic.NET …
Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
Viewers learn about the third conditional statement “else if” and use it in an example program. Then additional information about conditional statements is provided, covering the topic thoroughly. Viewers learn about the third conditional statement …
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

895 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now