Unknown frame size - java

Trying to get the frame size of an audio file I am getting instead -1. I tried to look for the interpretation of of this result in the JavaDoc but it does not mention anything big. Here's the source code :
import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;
/*....*/
File file = new File("/home/songs/audio.mp3");
MpegAudioFileReader mpegAudioFileReader = new MpegAudioFileReader();
AudioInputStream audioInputStream = mpegAudioFileReader.getAudioInputStream(file);
AudioFormat format = audioInputStream.getFormat();
long frameSize = format.getFrameSize();//frameSize = -1
float frameRate = format.getFrameRate();//frameRate = 38.28125
Inspecting he format object gives this : MPEG1L3 44100.0 Hz, unknown bits per sample, stereo, unknown frame size, 38.28125 frames/second,
I do not know why the frame size is unknown although it does appear on my audio file properties :
Any help is more than appreciated. Thanks.

getFormat() etc is implemented by the MPEG guys so it returns what they have - probably they left this blank or unable to extract;
If you put another .wav file you will probably get 2:
try {
audioInputStream=AudioSystem.getAudioInputStream(new File(".......wav"));
System.out.println(audioInputStream.getFormat().getFrameSize());
} catch (Exception e) {
e.printStackTrace();
}
Other notes: I dont see the Frame size in your display; it's rather the sample/bit rate so be sure to differentiate about that.
But for mp3 you have to live with that.
You can also create your own format if that helps - dont know your application
AudioFormat format = audioInputStream.getFormat();
newFormat=new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
format.getSampleRate(),
16,
format.getChannels(),
format.getChannels() * 2,
format.getSampleRate(),
false);

Related

MP3 Files get distorted during read process

I'm currently working on an application that plays back sound. I implemented playback for standard WAV File with the Java Sound API, no problems there, everything working fine. Now I want to add support for MP3 as well, but I'm having a strange problem: the playback gets distorted. I'm trying to figure out what I'm doing wrong, I would appreciate any leads in the right direction.
I'm using the Mp3SPI (http://www.javazoom.net/mp3spi/documents.html) for playing back the Mp3 Files.
I have already tried to take a look at the output and recorded a wav-file with the output I get from the mp3, then I compared the waveforms of the original and the recorded file. As it turns out, in the recorded file there are a lot of samples that are 0, or very close to it. Longer tones get broken up and the waveform returns to 0 all the time, then jumping back to the place the waveform is in the original.
I open the file like this:
private AudioInputStream mp3;
private AudioInputStream rawMp3;
private void openMP3(File file) {
// open the Audio INput Stream
try {
rawMp3 = AudioSystem.getAudioInputStream(file);
AudioFormat baseFormat = rawMp3.getFormat();
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false);
mp3 = AudioSystem.getAudioInputStream(decodedFormat, rawMp3);
} catch (UnsupportedAudioFileException | IOException ex) {
Logger.getLogger(SoundFile.class.getName()).log(Level.SEVERE, null, ex);
}
}
The part where I read the Mp3 File:
byte[] data = new byte[length];
// read the data into the buffer
int nBytesRead = 0;
while (nBytesRead != - 1 && nBytesRead < length) {
nBytesRead = mp3.read(data, 0, data.length - nBytesRead);
}
Also I convert the byte-array to doubles, perhaps I do something wrong here (I'm fairly new to using bitwise operators, so maybe there is the problem
double[][] frameBuffer = new double[2][1024]; // 2 channel stereo buffer
int nFramesRead = 0;
int byteIndex = 0;
// convert the data into double and write it to frameBuffer
for (int i = 0; i < length; ++i) {
for (int c = 0; c < 2; ++c) {
byte a = data[byteIndex++];
byte b = data[byteIndex++];
int val = a | b << 8; // a is the least significant byte. | functions as a + here. b << 8 moves 8 zeroes to the end of b.
frameBuffer[c][i] = (double) val / (double) Short.MAX_VALUE;
nFramesRead++;
}
}
The double-array is then later used to play back the sound. When playing a wav file, I do the exact same thing to the buffer, so I'm pretty sure it has to be something during the read process, not me sending faulty bytes to the ouput.
I would expect this to work out of the box with Mp3SPI, but somehow something breaks the audio along the way.
I am also open to trying other libraries to play back the MP3, if you have any recommendations. Just a Decoder for the raw MP3 Data would actually be enough.
As it turns out, the AudioFormat from the mp3 (input) and the AudioFormat of the output didnt match, obviously resulting in distortion. So with those matched up, playback is fine!

Java writing output AudioInputStream + AudioFormat set wFormat to FLOAT?

I've confirmed my program "works" with a variety of signed integer output formats. However, when I attempt to use 32-bit floating point, the output audio metadata indicates it to be 32-bit signed integer, and this results in broken playback.
Here's my audio format:
AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_FLOAT,
48000, // Hz sample rate
32, // bits per sample
2, // channels
8, // bytes per frame
48000, // Hz frame rate
false), // not big-endian
This is sent to a processor function (which I've confirmed "works" using other output formats):
public void mixToFile(AudioFormat format,
String outputPath,
int totalFrames) throws Exception {
ByteBuffer outputBytes = byteBufferOf(mix()); // the big show
AudioInputStream ais = new AudioInputStream(
new ByteArrayInputStream(outputBytes.array()), outputFormat,
totalFrames
);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File(outputPath));
}
The result is failure; the file has metadata format 32-bit signed int, see:
Playing WAVE '/tmp/output.wav' : Signed 32 bit Little Endian, Rate 48000 Hz, Stereo
I'm looking for the equivalent of How to write wav file with 32-bit float data?
which I've dealt with before, manually setting the wFormat tag in the 'fmt' chunk to WAVE_FORMAT_IEEE_FLOAT (3) when writing a RIFF container.
Is it possible to achieve this using AudioSystem.write, AudioInputStream and AudioFormat?

Weird behaviout of Java AudioFormat when bits per sample change

I am trying to play a audio stream that is returned to me by a server via UDP. The server uses DPCM to encode the audio, thus every byte contains two audio samples. When I play the audio with 8 bits/sample everything works fine, but when I try with 16 doing AudioFormat DPCM = new AudioFormat(8000,16,1,true,false); the clip is shorter and not so clear. What am I doing wrong?
ByteArrayOutputStream sound_buffer = new ByteArrayOutputStream();
clientRequest = new DatagramPacket( sound_request_buffer, sound_request_buffer.length );
server.send(clientRequest);
for(int i=0;i<100;i++){
buffer = new byte[128];
serverResponse = new DatagramPacket( buffer, buffer.length);
client.receive(serverResponse);
sound_buffer.write(buffer);
}
byte[] encoded_sound = sound_buffer.toByteArray();
byte[] decoded_sound = new byte[2*encoded_sound.length];
byte msnibble = (byte)((encoded_sound[0]>>4) & 0x000F);
decoded_sound[0] = (byte)(msnibble - 8);
byte lsnibble = (byte)(encoded_sound[0] & 0x000F );
decoded_sound[1] = (byte) (decoded_sound[0] + lsnibble - 8);
for(int i=1;i<encoded_sound.length;i++){
msnibble = (byte)((encoded_sound[i] >> 4) & 0x000F);
decoded_sound[2*i] = (byte)(decoded_sound[2*i-1] + msnibble - 8);
lsnibble = (byte)(encoded_sound[i] & 0x000F );
decoded_sound[2*i+1] = (byte)(decoded_sound[2*i] + lsnibble - 8);
}
AudioFormat DPCM = new AudioFormat(8000,8,1,true,false);
SourceDataLine lineOut=AudioSystem.getSourceDataLine(DPCM);
lineOut.open(DPCM,decoded_sound.length);
lineOut.start();
lineOut.write(decoded_sound,0,decoded_sound.length);
The problem is that you are giving the SourceDataLine 8-bit audio and telling it to play it as if it were 16-bit audio. This will make it halve the playback time (because it uses twice the number of bits per sample). It also does weird stuff with the actual numbers that are used for the sound, but I'm not exactly sure what (I haven't tested your example.)
The AudioFormat doesn't format the audio, it tells the SourceDataLine how your audio is currently formatted so that it plays it correctly.
I'm not really sure what you want to do, and I guess it would depend on why you want 16-bit audio. You might need to request 16-bit audio from the server instead of 8-bit, or you might not even need the audio to be 16-bit.

How can I convert a wav file in java

How can I convert a wav file in java
AudioFormat targetFormat = new AudioFormat(
sourceFormat.getEncoding(),
fTargetFrameRate,
16,
sourceFormat.getChannels(),
sourceFormat.getFrameSize(),
fTargetFrameRate,
false);
in result Exception :
java.lang.IllegalArgumentException: Unsupported conversion:
ULAW 8000.0 Hz, **16 bit**, mono, 1 bytes/frame, **from** ULAW 8000.0 Hz, **8 bit**, mono, 1 bytes/frame
it is possible in java?
I need get wav file 16 bit, from 8
Here is a method that will convert an 8-bit uLaw encoded binary file into a 16-bit WAV file using built-in Java methods.
public static void convertULawFileToWav(String filename) {
File file = new File(filename);
if (!file.exists())
return;
try {
long fileSize = file.length();
int frameSize = 160;
long numFrames = fileSize / frameSize;
AudioFormat audioFormat = new AudioFormat(Encoding.ULAW, 8000, 8, 1, frameSize, 50, true);
AudioInputStream audioInputStream = new AudioInputStream(new FileInputStream(file), audioFormat, numFrames);
AudioSystem.write(audioInputStream, Type.WAVE, new File("C:\\file.wav"));
} catch (IOException e) {
e.printStackTrace();
}
}
Look at this one: Conversion of Audio Format it is similar to your issue suggesting looking at http://docs.oracle.com/javase/6/docs/api/javax/sound/sampled/AudioSystem.html
You can always use FFMPEG, http://ffmpeg.org/, to do the conversion. Your Java program can call FFMPEG to do the conversion.
FFMPEG works on all OS.

Java spectrogram images: mp3 and microphone

First of all i'm working on a little project to see the spectrum from some sounds.
I got this working with a microphone:
alt text http://img25.imageshack.us/img25/4271/spectrumanalyzerfourier.png
The image above is just me talking and shouting through a microphone for a few seconds. This looks good to me.
But when I try to read an MP3 file and make a spectogram image of it it looks a bit different. I tried the Aphex Twin - Windowlicker where you should normally see a face in the spectrogram image or at least some more darker colors. But it doesn't look so good:
alt text http://img10.imageshack.us/img10/3475/aphextwinhmm.png
Here is what I did with the microphone:
byte tempBuffer[] = new byte[10000];
ByteArrayOutputStream out = new ByteArrayOutputStream();
counter = 20;
// Microphone
while (counter != 0) {
int count = line.read(tempBuffer, 0, tempBuffer.length);
if (count > 0) {
out.write(tempBuffer, 0, count);
}
counter--;
}
out.close();
// FFT code below ...
byte audio[] = out.toByteArray();
// ...
And this is how I do it with the MP3:
I used the same code to do the transformation and visualization only the audio capturing part is different (I only adjusted the hight in the drawing method to see if there is a difference but there wasn't one):
byte tempBuffer[] = new byte[10000];
ByteArrayOutputStream out = new ByteArrayOutputStream();
FileInputStream input = null;
File mp3 = new File("Aphex Twin - Widowlicker.mp3");
input = new FileInputStream(mp3);
int len;
while((len = input.read(tempBuffer)) > 0) {
out.write(tempBuffer, 0, len);
}
out.close();
input.close();
// FFT code below ...
byte audio[] = out.toByteArray();
// ...
It would be nice if somebody could point me out what I am doing wrong with the MP3 file.
These are my settings:
Sample rate: 44100
Bit per sample: 8
Channels: 1 (mono)
signed: true
big endian: true (i'm using AudioFormat in Java)
tempBuffer to read audio: 10000 ( byte tempBuffer[] = new byte[10000]; )
and for the FFT I split the audio in chuncks of 4096 (must be a power of 2)
By the way: are these settings ok or should I use 16bps or stereo or is 10000 for the buffer too much or 4096 to small/big ?
Thanks in advance
MP3 is a compressed audio format. You should first decompress the data before you can use it as an audio stream comparable to the data from your microphone. The raw MP3 data has maximum entropy and should look much like white noise, which it does in you spectrogram.

Categories