[java-dev] Bug in AudioFileBuffer with different sample sizes?
topher lafata
topher at topher.com
Sat Mar 22 11:44:42 MDT 2008
- Previous message: [java-dev] Bug in AudioFileBuffer with different sample sizes?
- Next message: [java-dev] Bug in AudioFileBuffer with different sample sizes?
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
i dont think you have overlooked anything. it is very possible there
are bugs with those bit depths.
Regardless here is the source for the class. You could copy it and
make your own.
package com.cycling74.msp;
import com.cycling74.max.MessageReceiver;
import javax.sound.sampled.*;
import java.io.FileNotFoundException;
import java.io.*;
/**
* A utility class for loading audio data off of disk and into
memory. The data is translated from the
* native file format into the the floating point format used by msp.
* @author Topher LaFata
*/
public class AudioFileBuffer
{
/**
* If an instance of MessageReceiver is passed into the constructor
the FINISHED_READING message will be
* sent to it when the requested file is successfully loaded into
memory. File loading occurs asynchronously.
*/
public static final int FINISHED_READING = 1;
//file writing is not yet implemented
//public static final int FINISHED_WRITING = 2;
private File _file;
private AudioInputStream _ais;
private AudioFormat _aformat;
private int _num_channels;
private long _framelength; //length of current file is frames
private int _framesize;//size of each frame in bytes
private int _sample_size_in_bits;
private boolean _big_endian;
private float _sr;
/**
* buf contains the audio samples loaded off of disk deinterleaved by
channel into a 2 dimensional
* floating point array. The first dimension corresponds to the audio
channel and the second dimension
* corresponds to the audio data itself. Thus a stereo audio file
would have the samples for the left channel
* at buf[0][0...framelength - 1] and the right channel at buf[1]
[0...framelength - 1]
*/
public float[][] buf;
//this is affected by sample rate
private MessageReceiver _client = null;
private buf_filler _bft;
/**
* Constructor.
* @param filename Absolute native path of the audio file to be
loaded into memory.
*/
public AudioFileBuffer(String filename)throws
FileNotFoundException, IOException, UnsupportedAudioFileException
{
_client = null;
openmp3(filename);
}
/**
* Constructor.
* @param filename Absolute native path of the audio file to be
loaded into memory.
* @param client instance of MessageReceiver which will be notified
when file is finished being loaded into memory.
* This information may or may not be relevant since the member
buffer,buf[][], containing the audio data will be valid and zero filled
* when the constructor returns.
*/
public AudioFileBuffer(String filename, MessageReceiver client)
throws FileNotFoundException, IOException, UnsupportedAudioFileException
{
_client = client;
open(filename);
}
public void openmp3(String filename)throws FileNotFoundException,
IOException, UnsupportedAudioFileException
{
_file = new File(filename);
if(!_file.exists())
throw new FileNotFoundException("Unable to find file "+filename);
kill_buf_filler();
AudioFileFormat baseFileFormat = null;
AudioFormat baseFormat = null;
baseFileFormat = AudioSystem.getAudioFileFormat(_file);
baseFormat = baseFileFormat.getFormat();
// Audio type such as MPEG1 Layer3, or Layer 2, or ...
System.out.println("FORMAT "+baseFileFormat.getType().toString());
// System.out.println("sr is "+baseFormat.getSampleRate());
// System.out.println("channels is "+baseFormat.getChannels());
// System.out.println("frame rate is "+baseFormat.getFrameRate());
// System.out.println("frame size is "+baseFormat.getFrameSize());
// System.out.println("is big endian "+baseFormat.isBigEndian());
AudioInputStream in = AudioSystem.getAudioInputStream(_file);
System.out.println("ms is "+in.markSupported());
System.out.println("mp3 fl is "+in.getFrameLength());
//AudioFormat baseFormat = in.getFormat();
AudioFormat decodedFormat =
new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels()*2,
baseFormat.getSampleRate(),true) ;
_ais = AudioSystem.getAudioInputStream(decodedFormat, in);
//find the length of the converted mp3 in frames.
//unfortunately we don't get this with the whole new _ais decoded crap
//we make ll one frame in length
int framelength = baseFormat.getChannels()*2;
System.out.println("framelength is "+framelength);
byte[] ll = new byte[framelength];
int l = ll.length;
int totframes = 0;
int bytesread = 0;
while((bytesread = _ais.read(ll,0,framelength)) != -1)
{
totframes++;
if(bytesread < framelength)
{
System.out.println("read lesss than framelength "+bytesread);
}
}
System.out.println("frame length is "+totframes);
System.out.println("ais is "+_ais.markSupported());
_ais = AudioSystem.getAudioInputStream(decodedFormat, in);
_aformat = _ais.getFormat();
// System.out.println("sr is "+_aformat.getSampleRate());
// System.out.println("channels is "+_aformat.getChannels());
// System.out.println("frame rate is "+_aformat.getFrameRate());
// System.out.println("frame length is "+_ais.getFrameLength());
// System.out.println("frame size is "+_aformat.getFrameSize());
// System.out.println("is big endian "+_aformat.isBigEndian());
// System.out.println("s size in bits "+_aformat.getSampleSizeInBits
());
_sr = _aformat.getSampleRate();
_num_channels = _aformat.getChannels();
_framelength = totframes;
_framesize = framelength;
_sample_size_in_bits = _aformat.getSampleSizeInBits();
_big_endian = _aformat.isBigEndian();
buf = new float[_num_channels][(int)_framelength];
_bft = new buf_filler(this);
_bft.start();
}
/**
* Load a different audio file into memory using this instance
of AudioFileBuffer. Previous audio data is disgarded and
* buf[][] member variable reflects the number of channels and
framesize of the new audio file..
* @param filename Absolute native path of the audio file to be
loaded into memory.
*/
public void open(String filename)throws FileNotFoundException,
IOException, UnsupportedAudioFileException
{
_file = new File(filename);
if(!_file.exists())
throw new FileNotFoundException("Unable to find file "+filename);
//kill the previous buf filler if it is already running
kill_buf_filler();
//This is so we have mark supported and get efficiency in our disk
reads
InputStream fileInputStream = new FileInputStream(_file);
InputStream inputStream = new BufferedInputStream(fileInputStream);
try{
_ais = AudioSystem.getAudioInputStream(inputStream);
}catch(IOException ioe)
{
throw ioe;
}
catch(UnsupportedAudioFileException uafe)
{
throw uafe;
}
_aformat = _ais.getFormat();
if(_aformat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED)
{
throw new UnsupportedAudioFileException("AudioBuffer currently
only supports"+
" PCM_SIGNED encodings");
}
_sr = _aformat.getSampleRate();
_num_channels = _aformat.getChannels();
_framelength = _ais.getFrameLength();
_framesize = _aformat.getFrameSize();
_sample_size_in_bits = _aformat.getSampleSizeInBits();
_big_endian = _aformat.isBigEndian();
buf = new float[_num_channels][(int)_framelength];
_bft = new buf_filler(this);
_bft.start();
}
/**
* Get the sample rate of the current audio file. It is important
to note that
* the current msp sampling rate is currently not considered when
the audio file
* is being decoded from disk. This means that an audio file saved
with a different
* sampling rate from the current msp sampling rate needs
additional sample rate conversion
* done on its audio data after it is loaded to play back at the
expected speed.
* This conversion is currently not done by default.
*/
public float getSampleRate()
{
return _sr;
}
/*
public AudioFormat getAudioFormat()
{
return _aformat;
}
*/
/**
* Get the sample size in bits of the current audio file. For
example, 8,16,24.
*/
public int getSampleSizeInBits()
{
return _sample_size_in_bits;
}
/**
* Was the current audio file big endian format.
*/
public boolean isBigEndian()
{
return _big_endian;
}
/**
* Get the number of sample frames in the audio file.A frame consists of
* sample data for all channels at a particular instant in time.Thus
a mono
* audio file which has 1000 samples will have a frame length of 1000
with
* each frame containing one sample. A stereo audio file with 2000
samples would
* have a frame length of 1000 with each frame containing 2 samples,
one for each
* the left and right channels.
*/
public long getFrameLength()
{
return _framelength;
}
/**
* Get the number of channels of the current audio file.
*/
public int getChannels()
{
return _num_channels;
}
/**
*Get the length of the current audio file in milliseconds.
* This is equivalent to:
*<pre>
* frame length / (sample rate / 1000)
*</pre>
*/
public float getLengthMs()
{
return (float)(_framelength / (getSampleRate() / 1000));
}
private void fill_buf()
{
System.out.println("filling buf");
byte[] tmp = new byte[2048];
int bytesread = 0;
short ss = 0;
int si = 0;
int wh = 0;//points to sample frame
try{
while((bytesread = _ais.read(tmp,0,tmp.length)) > 0)
{
if(wh % 1000 == 0)
System.out.println("wh is "+wh);
for(int i = 0; i < bytesread;i+= _framesize)
{
//if it is not bigendian make it so now...
//this is happening per frame..maybe not the best approach
if(!_big_endian && _sample_size_in_bits > 8)
{
byte t1 = 0;
switch(_sample_size_in_bits)
{
case 16:
for(int ii = i; ii < i + _framesize;ii += 2)
{
t1 = tmp[ii];
tmp[ii] = tmp[ii+1];
tmp[ii +1] = t1;
}
break;
case 24:
for(int ii = i; ii < i + _framesize;ii += 3)
{
t1 = tmp[ii];
tmp[ii] = tmp[ii+3];
tmp[ii +3] = t1;
}
break;
default:
}
}
//deinterleave and convert to float
for(int c = 0;c < _num_channels;c++)
{
int ch_offset = (c * _num_channels);
switch (_sample_size_in_bits)
{
case 8:
ss = (short)(tmp[i+c] & 0xff);
buf[c][wh] = (float)ss/16384;
break;
case 16:
ss = (short)(((tmp[i+ch_offset] & 0xff) << 8) | (tmp[i
+ch_offset+1] & 0xff));
buf[c][wh] = (float)ss/Short.MAX_VALUE;
if(wh % 1024 == 0)
System.out.println(ss);
break;
case 24:
si = (int)( ((tmp[i+ch_offset] & 0xff) << 16) | ((tmp[i
+ch_offset+1] & 0xff) << 8) | (tmp[i+ch_offset+2] & 0xff));
buf[c][wh] = (float)si/8388608;
break;
default:
}
}
wh++;
}
}
_ais.close();
if(_client != null)
{
System.out.println("done converting to float");
_client.messageReceived(this,FINISHED_READING,null);
}
}catch(Exception e)
{
e.printStackTrace();
}
}
t
On Mar 22, 2008, at 04:30 AM, volker böhm wrote:
> hallo,
> i'm using AudioFileBuffer from the max mxj api to read soundfiles
> with varying sample sizes.
> when i try to output the floating point data from the buf field, i
> get correct results only for 16 bit files.
> 8 bit, 24 bit and 32 bit are all wrong, which to me looks like
> errors in int-to-float-conversion.
> do i overlook something here?
> thanks, volker.
>
> simple test class:
>
> import com.cycling74.max.*;
> import com.cycling74.msp.*;
>
> public class test_afb extends MaxObject
> {
> private AudioFileBuffer afb = null;
>
> public test_afb (Atom[] args) {
> declareInlets(new int[]{DataTypes.ALL});
> declareOutlets(new int[]{DataTypes.ALL});
> }
>
> /* load
> soundfile----------------------------------------------------*/
> publicvoid open( String path ) {
> String fname = MaxSystem.locateFile(path);
> post("filename: "+fname);
>
> try {
> afb = new AudioFileBuffer(fname);
> System.out.println("frame length: "+ afb.getFrameLength());
> System.out.println("samp size in bits: "+
> afb.getSampleSizeInBits());
> System.out.println("num channels: "+ afb.getChannels());
> System.out.println("big endian: "+ afb.isBigEndian());
> System.out.println("sample rate: "+ afb.getSampleRate());
> }
> catch(Exception e) {
> error("mxj test_afb: sorry, can't open that file!");
> }
> }
>
> /* output sample value at index from channel 1-------------------*/
> publicvoid inlet (int index) {
> outlet(0, afb.buf[0][index]);
> }
> }
>
>
> simple test patch:
>
> #P window setfont "Sans Serif" 9.;
> #P flonum 225 196 67 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
> #P flonum 93 194 67 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
> #P number 225 121 44 9 0 0 1 3 0 0 0 221 221 221 222 222 222 0 0 0;
> #P window linecount 1;
> #P newex 225 166 54 196617 peek~ aha;
> #P newex 93 117 68 196617 prepend open;
> #P newex 93 166 93 196617 mxj test_afb;
> #P newex 351 118 81 196617 prepend replace;
> #P button 93 39 15 0;
> #P newex 93 62 56 196617 opendialog;
> #P newex 351 140 83 196617 buffer~ aha 100;
> #P comment 217 105 100 196617 sample index;
> #P fasten 8 0 5 0 230 151 98 151;
> #P connect 8 0 7 0;
> #P connect 5 0 9 0;
> #P connect 6 0 5 0;
> #P connect 3 0 2 0;
> #P connect 2 0 6 0;
> #P connect 7 0 10 0;
> #P fasten 2 0 4 0 98 88 356 88;
> #P connect 4 0 1 0;
> #P window clipboard copycount 11;
> _______________________________________________
> java-dev mailing list
> java-dev at cycling74.com
> http://www.cycling74.com/mailman/listinfo/java-dev
- Previous message: [java-dev] Bug in AudioFileBuffer with different sample sizes?
- Next message: [java-dev] Bug in AudioFileBuffer with different sample sizes?
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
