/* * 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 ***/