Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Getting Peak Information from AudioInputStream... the code works, but...

843802Jun 4 2008 — edited Sep 6 2008
Hello Javax.Sound users. I hope somebody can help. I've written a class based on JLayer following the model here . I want to analyze the peak values in a sound file. Everything seems to work and the milliseconds work out, but a quick look in Audacity reveals that I'm doing something horribly wrong. The peak data have very little to do with the correct data (and graphing it looks even more random). Here's the code. Thanks in advance to everyone for your help.
package whatAmIDoingWrong;

import java.io.File;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

public class AnalyzeMp3 {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		new AnalyzeMp3("D:/music/Learning Rhythms/Las Claves/20 120 - 120.mp3");
	}
	
	private int lastByteProcessed = 0;
	private double  bytesPerFrame = 0;
	private double framesPerMillisecond = 0;
	private double getLastByteProcessedInMilliseconds() {
		double retVal = lastByteProcessed/bytesPerFrame*framesPerMillisecond;
		return retVal;
	}
	

	public AnalyzeMp3(String filename) throws Exception 
	{
		File file = new File(
		filename);
		if (!file.exists()) {
			System.out.println("File not found, sorry");
			return;
		} 
		AudioInputStream in = AudioSystem.getAudioInputStream(file);
		AudioInputStream din = null;
		AudioFormat baseFormat = in.getFormat();
		AudioFormat decodedFormat = new AudioFormat(
				AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(),
				16, baseFormat.getChannels(), baseFormat.getChannels() * 2,
				baseFormat.getSampleRate(), false);
		din = AudioSystem.getAudioInputStream(decodedFormat, in);

		// members
		bytesPerFrame =
			decodedFormat.getSampleSizeInBits()/8*decodedFormat.getChannels();
		framesPerMillisecond = 1000/decodedFormat.getSampleRate();
		
		
		// Play it or analyze it
		int length = playIt(decodedFormat, din, false);
		System.out.println("samples=" + length/bytesPerFrame + 
				" so total seconds=" +
				(float)length/bytesPerFrame/decodedFormat.getSampleRate());
		in.close();
	}	
	
	/* returns the number of samples just to make sure we're on track */
	private int playIt(AudioFormat targetFormat, AudioInputStream din, boolean playAlso) throws Exception {
		SourceDataLine line = null;
		if (playAlso) {
			line = getLine(targetFormat);
			line.start();
		}
		
		int retVal = 0;
		byte[] data = new byte[1024];
		int nBytesRead = 0;
		while (nBytesRead != -1) {
			nBytesRead = din.read(data, 0, data.length);
			if (nBytesRead != -1) {
				retVal += nBytesRead;
				if (playAlso) {
					line.write(data, 0, nBytesRead);
				}
				process(data, targetFormat.getChannels());
			}
		}
		if (playAlso) {
			line.drain();
		    line.stop();
		    line.close();			
		}
		din.close();
		return retVal;
	}

	

	private static SourceDataLine getLine(AudioFormat audioFormat) throws Exception {
		SourceDataLine res = null;
		DataLine.Info info = new DataLine.Info(SourceDataLine.class,
				audioFormat);
		res = (SourceDataLine) AudioSystem.getLine(info);
		res.open(audioFormat);
		return res;
	}

	
	public void process(byte[] data, int numOfChannels) {
		int numOfSamples = data.length / 2; // two bytes per sample
		numOfSamples = numOfSamples / numOfChannels; // two samples, one
		// for each channel
		int offset = 0;

		// init the max values
		int[] maxValue = new int[numOfChannels]; // one max per channel
		for (int channel=0; channel<numOfChannels;channel++) {
			maxValue[channel]=0; 
		}
		
		// run through the frames, analyzing each one
		for (int i = 0; i < numOfSamples; i++) {
			// run through the channels which gives us the sample
			for (int channel=0; channel<numOfChannels; channel++) {
				// we take the short and strip the sign to get the volume data 0-32K
				int sample = Math.abs(arr2int(data, offset, false));
				offset = offset + 2;
				lastByteProcessed = lastByteProcessed + 2;
				if (sample > maxValue[channel])
					maxValue[channel] = sample;
			}
		}
		System.out.print("Peak ms=" + (int)getLastByteProcessedInMilliseconds());
		for (int channel=0; channel<numOfChannels;channel++) {
			int peak = maxValue[channel];
			System.out.print(", peak=" + Math.round(getDbValue(peak)));
		}
		System.out.println();
	}
	

	public static short arr2int(byte[] buffer, int offset, boolean bigEndian) {
		short sample;
		if (bigEndian) {
			sample = (short)
			(  (buffer[offset + 0] << 8)
			 | (buffer[offset + 1] & 0xFF) );	
		} else {
			sample = (short)
			(  (buffer[offset + 0] & 0xFF)
			 | (buffer[offset + 1] << 8)  );		
		}
		return sample;
	}
	
	public static double getDbValue(int peak) {
		if (peak == 0)
			return 0;
		else return 20 * Math.log10((double)peak/ 32768) + 96;
	}
}
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Oct 4 2008
Added on Jun 4 2008
4 comments
329 views