/*
* TAsynchronousFilteredAudioInputStream.java
*
* This file is part of Tritonus: http://www.tritonus.org/
*/
/*
* Copyright (c) 1999, 2000 by Matthias Pfisterer
* Copyright (c) 2012 by fireandfuel from Cuina Team (http://www.cuina.byethost12.com/)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
package sound.tritonus;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
/**
* Base class for asynchronous converters. This class serves as base class for
* converters that do not have a fixed ratio between the size of a block of
* input data and the size of a block of output data. These types of converters
* therefore need an internal buffer, which is realized in this class.
*
* @author Matthias Pfisterer
*/
public abstract class TAsynchronousFilteredAudioInputStream extends TAudioInputStream implements
TCircularBuffer.Trigger
{
private static final int DEFAULT_BUFFER_SIZE = 327670;
private static final int DEFAULT_MIN_AVAILABLE = 4096;
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
private TCircularBuffer m_circularBuffer;
private int m_nMinAvailable;
private byte[] m_abSingleByte;
/**
* Constructor. This constructor uses the default buffer size and the
* default min available amount.
*
* @param lLength
* length of this stream in frames. May be
* AudioSystem.NOT_SPECIFIED.
*/
public TAsynchronousFilteredAudioInputStream(AudioFormat outputFormat, long lLength)
{
this(outputFormat, lLength, DEFAULT_BUFFER_SIZE, DEFAULT_MIN_AVAILABLE);
}
/**
* Constructor. With this constructor, the buffer size and the minimum
* available amount can be specified as parameters.
*
* @param lLength
* length of this stream in frames. May be
* AudioSystem.NOT_SPECIFIED.
* @param nBufferSize
* size of the circular buffer in bytes.
*/
public TAsynchronousFilteredAudioInputStream(AudioFormat outputFormat, long lLength,
int nBufferSize, int nMinAvailable)
{
/*
* The usage of a ByteArrayInputStream is a hack. (the infamous
* "JavaOne hack", because I did it on June 6th 2000 in San Francisco,
* only hours before a JavaOne session where I wanted to show mp3
* playback with Java Sound.) It is necessary because in the FCS version
* of the Sun jdk1.3, the constructor of AudioInputStream throws an
* exception if its first argument is null. So we have to pass a dummy
* non-null value.
*/
super(new ByteArrayInputStream(EMPTY_BYTE_ARRAY), outputFormat, lLength);
m_circularBuffer = new TCircularBuffer(nBufferSize, false, // blocking
// read
true, // blocking write
this); // trigger
m_nMinAvailable = nMinAvailable;
}
/**
* Returns the circular buffer.
*/
protected TCircularBuffer getCircularBuffer()
{
return m_circularBuffer;
}
/**
* Check if writing more data to the circular buffer is recommended. This
* checks the available write space in the circular buffer against the
* minimum available property. If the available write space is greater than
* the minimum available property, more writing is encouraged, so this method
* returns true. Note that this is only a hint to subclasses. However, it is
* an important hint.
*
* @return true if more writing to the circular buffer is recommended.
* Otherwise, false is returned.
*/
protected boolean writeMore()
{
return getCircularBuffer().availableWrite() > m_nMinAvailable;
}
public int read() throws IOException
{
// if (TDebug.TraceAudioConverter) {
// TDebug.out("TAsynchronousFilteredAudioInputStream.read(): begin"); }
int nByte = -1;
if(m_abSingleByte == null)
{
m_abSingleByte = new byte[1];
}
int nReturn = read(m_abSingleByte);
if(nReturn == -1)
{
nByte = -1;
} else
{
// $$fb 2001-04-14 nobody really knows that...
nByte = m_abSingleByte[0] & 0xFF;
}
// if (TDebug.TraceAudioConverter) {
// TDebug.out("TAsynchronousFilteredAudioInputStream.read(): end"); }
return nByte;
}
public int read(byte[] abData) throws IOException
{
int nRead = read(abData, 0, abData.length);
return nRead;
}
public int read(byte[] abData, int nOffset, int nLength) throws IOException
{
int nRead = m_circularBuffer.read(abData, nOffset, nLength);
return nRead;
}
public long skip(long lSkip) throws IOException
{
// TODO: this is quite inefficient
for(long lSkipped = 0; lSkipped < lSkip; lSkipped++)
{
int nReturn = read();
if(nReturn == -1)
{
return lSkipped;
}
}
return lSkip;
}
public int available() throws IOException
{
return m_circularBuffer.availableRead();
}
public void close() throws IOException
{
m_circularBuffer.close();
}
public boolean markSupported()
{
return false;
}
public void mark(int nReadLimit)
{
}
public void reset() throws IOException
{
throw new IOException("mark not supported");
}
}
/*** TAsynchronousFilteredAudioInputStream.java ***/