Package org.sound.sampled.file

Source Code of org.sound.sampled.file.TAudioFileReader

/*
* Copyright (C) 1999 Matthias Pfisterer
*               2001 Florian Bomers
*               2013 Trilarion
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.sound.sampled.file;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.sound.sampled.spi.AudioFileReader;
import org.sound.TDebug;

/**
* Base class for audio file readers. This is Tritonus' base class for classes
* that provide the facility of detecting an audio file type and reading its
* header. Classes should be derived from this class or one of its subclasses
* rather than from javax.sound.sampled.spi.AudioFileReader.
*
*/
public abstract class TAudioFileReader extends AudioFileReader {

    private int m_nMarkLimit = -1;
    private boolean m_bRereading;

    protected TAudioFileReader(int nMarkLimit) {
        this(nMarkLimit, false);
    }

    protected TAudioFileReader(int nMarkLimit, boolean bRereading) {
        m_nMarkLimit = nMarkLimit;
        m_bRereading = bRereading;
    }

    private int getMarkLimit() {
        return m_nMarkLimit;
    }

    private boolean isRereading() {
        return m_bRereading;
    }

    /**
     * Get an AudioFileFormat object for a File. This method calls
     * getAudioFileFormat(InputStream, long). Subclasses should not override
     * this method unless there are really severe reasons. Normally, it is
     * sufficient to implement getAudioFileFormat(InputStream, long).
     *
     * @param file  the file to read from.
     * @return  an AudioFileFormat instance containing information from the
     * header of the file passed in.
     */
    @Override
    public AudioFileFormat getAudioFileFormat(File file)
            throws UnsupportedAudioFileException, IOException {
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioFileFormat(File): begin (class: " + getClass().getSimpleName() + ")");
        }
        long lFileLengthInBytes = file.length();
        InputStream inputStream = new FileInputStream(file);
        AudioFileFormat audioFileFormat = null;
        try {
            audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
        } finally {
            inputStream.close();
        }
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioFileFormat(File): end");
        }
        return audioFileFormat;
    }

    /**
     * Get an AudioFileFormat object for a URL. This method calls
     * getAudioFileFormat(InputStream, long). Subclasses should not override
     * this method unless there are really severe reasons. Normally, it is
     * sufficient to implement getAudioFileFormat(InputStream, long).
     *
     * @param url  the URL to read from.
     * @return  an AudioFileFormat instance containing information from the
     * header of the URL passed in.
     */
    @Override
    public AudioFileFormat getAudioFileFormat(URL url)
            throws UnsupportedAudioFileException, IOException {
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioFileFormat(URL): begin (class: " + getClass().getSimpleName() + ")");
        }
        long lFileLengthInBytes = getDataLength(url);
        InputStream inputStream = url.openStream();
        AudioFileFormat audioFileFormat = null;
        try {
            audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
        } finally {
            inputStream.close();
        }
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioFileFormat(URL): end");
        }
        return audioFileFormat;
    }

    /**
     * Get an AudioFileFormat object for an InputStream. This method calls
     * getAudioFileFormat(InputStream, long). Subclasses should not override
     * this method unless there are really severe reasons. Normally, it is
     * sufficient to implement getAudioFileFormat(InputStream, long).
     *
     * @param inputStream  the stream to read from.
     * @return  an AudioFileFormat instance containing information from the
     * header of the stream passed in.
     */
    @Override
    public AudioFileFormat getAudioFileFormat(InputStream inputStream)
            throws UnsupportedAudioFileException, IOException {
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): begin (class: " + getClass().getSimpleName() + ")");
        }
        long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
        if (!inputStream.markSupported()) {
            inputStream = new BufferedInputStream(inputStream, getMarkLimit());
        }
        inputStream.mark(getMarkLimit());
        AudioFileFormat audioFileFormat = null;
        try {
            audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
        } finally {
            /* TODO: required semantics is unclear: should reset()
             be executed only when there is an exception or
             should it be done always?
             */
            inputStream.reset();
        }
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): end");
        }
        return audioFileFormat;
    }

    /**
     * Get an AudioFileFormat (internal implementation). Subclasses must
     * implement this method in a way specific to the file format they handle.
     * Note that depending on the implementation of this method, you should or
     * should not override getAudioInputStream(InputStream, long), too (see
     * comment there).
     *
     * @param inputStream The InputStream to read from. It should be tested if
     * it is markable. If not, and it is re-reading, wrap it into a
     * BufferedInputStream with getMarkLimit() size.
     * @param lFileLengthInBytes The size of the originating file, if known. If
     * it isn't known, AudioSystem.NOT_SPECIFIED should be passed. This value
     * may be used for byteLength in AudioFileFormat, if this value can't be
     * derived from the information in the file header.
     * @return an AudioFileFormat instance containing information from the
     * header of the stream passed in as inputStream.
     */
    protected abstract AudioFileFormat getAudioFileFormat(
            InputStream inputStream, long lFileLengthInBytes)
            throws UnsupportedAudioFileException, IOException;

    /**
     * Get an AudioInputStream object for a file. This method calls
     * getAudioInputStream(InputStream, long). Subclasses should not override
     * this method unless there are really severe reasons. Normally, it is
     * sufficient to implement getAudioFileFormat(InputStream, long) and perhaps
     * override getAudioInputStream(InputStream, long).
     *
     * @param file  the File object to read from.
     * @return  an AudioInputStream instance containing the audio data from this
     * file.
     */
    @Override
    public AudioInputStream getAudioInputStream(File file)
            throws UnsupportedAudioFileException, IOException {
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioInputStream(File): begin (class: " + getClass().getSimpleName() + ")");
        }
        long lFileLengthInBytes = file.length();
        AudioInputStream audioInputStream = null;
        try (InputStream inputStream = new FileInputStream(file)) {
            audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
        } catch (UnsupportedAudioFileException | IOException e) {
            throw e;
        }
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioInputStream(File): end");
        }
        return audioInputStream;
    }

    /**
     * Get an AudioInputStream object for a URL. This method calls
     * getAudioInputStream(InputStream, long). Subclasses should not override
     * this method unless there are really severe reasons. Normally, it is
     * sufficient to implement getAudioFileFormat(InputStream, long) and perhaps
     * override getAudioInputStream(InputStream, long).
     *
     * @param url  the URL to read from.
     * @return  an AudioInputStream instance containing the audio data from this
     * URL.
     */
    @Override
    public AudioInputStream getAudioInputStream(URL url)
            throws UnsupportedAudioFileException, IOException {
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioInputStream(URL): begin (class: " + getClass().getSimpleName() + ")");
        }
        long lFileLengthInBytes = getDataLength(url);
        InputStream inputStream = url.openStream();
        AudioInputStream audioInputStream = null;
        try {
            audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
        } catch (UnsupportedAudioFileException | IOException e) {
            inputStream.close();
            throw e;
        }
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioInputStream(URL): end");
        }
        return audioInputStream;
    }

    /**
     * Get an AudioInputStream object for an InputStream. This method calls
     * getAudioInputStream(InputStream, long). Subclasses should not override
     * this method unless there are really severe reasons. Normally, it is
     * sufficient to implement getAudioFileFormat(InputStream, long) and perhaps
     * override getAudioInputStream(InputStream, long).
     *
     * @param inputStream  the stream to read from.
     * @return  an AudioInputStream instance containing the audio data from this
     * stream.
     */
    @Override
    public AudioInputStream getAudioInputStream(InputStream inputStream)
            throws UnsupportedAudioFileException, IOException {
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): begin (class: " + getClass().getSimpleName() + ")");
        }
        long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
        AudioInputStream audioInputStream = null;
        if (!inputStream.markSupported()) {
            inputStream = new BufferedInputStream(inputStream, getMarkLimit());
        }
        inputStream.mark(getMarkLimit());
        try {
            audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
        } catch (UnsupportedAudioFileException e) {
            inputStream.reset();
            throw e;
        } catch (IOException e) {
            try {
                inputStream.reset();
            } catch (IOException e2) {
                if (e2.getCause() == null) {
                    e2.initCause(e);
                    throw e2;
                }
            }
            throw e;
        }
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): end");
        }
        return audioInputStream;
    }

    /**
     * Get an AudioInputStream (internal implementation). This implementation
     * calls getAudioFileFormat() with the same arguments as passed in here.
     * Then, it constructs an AudioInputStream instance. This instance takes the
     * passed inputStream in the state it is left after getAudioFileFormat() did
     * its work. In other words, the implementation here assumes that
     * getAudioFileFormat() reads the entire header up to a position exactly
     * where the audio data starts. If this can't be realized for a certain
     * format, this method should be overridden.
     *
     * @param inputStream The InputStream to read from. It should be tested if
     * it is markable. If not, and it is re-reading, wrap it into a
     * BufferedInputStream with getMarkLimit() size.
     * @param lFileLengthInBytes The size of the originating file, if known. If
     * it isn't known, AudioSystem.NOT_SPECIFIED should be passed. This value
     * may be used for byteLength in AudioFileFormat, if this value can't be
     * derived from the information in the file header.
     */
    protected AudioInputStream getAudioInputStream(InputStream inputStream,
            long lFileLengthInBytes) throws UnsupportedAudioFileException,
            IOException {
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): begin (class: "
                    + getClass().getSimpleName() + ")");
        }
        if (isRereading()) {
            if (!inputStream.markSupported()) {
                inputStream = new BufferedInputStream(inputStream,
                        getMarkLimit());
            }
            inputStream.mark(getMarkLimit());
        }
        AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream,
                lFileLengthInBytes);
        if (isRereading()) {
            inputStream.reset();
        }
        AudioInputStream audioInputStream = new AudioInputStream(inputStream,
                audioFileFormat.getFormat(), audioFileFormat.getFrameLength());
        if (TDebug.TraceAudioFileReader) {
            TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): end");
        }
        return audioInputStream;
    }

    protected static int calculateFrameSize(int nSampleSize, int nNumChannels) {
        return ((nSampleSize + 7) / 8) * nNumChannels;
    }

    private static long getDataLength(URL url)
            throws IOException {
        long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
        URLConnection connection = url.openConnection();
        connection.connect();
        int nLength = connection.getContentLength();
        if (nLength > 0) {
            lFileLengthInBytes = nLength;
        }
        return lFileLengthInBytes;
    }
}
TOP

Related Classes of org.sound.sampled.file.TAudioFileReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.