All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jm.audio.io.AudioFileIn Maven / Gradle / Ivy

The newest version!
/*



Copyright (C) 2000 Andrew Sorensen & Andrew Brown

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or 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 General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

package jm.audio.io;

import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Vector;

/**
 * Audio file reading class for jMusic.
 * The class utilises the JavaSound file reading classes.
 * It works indepdently of the jMusic audio architecture used
 * for rendering scores, and is intended for use by simple file
 * manipulation utility programs operating asychronously (non real time).
 * This class deals with some the current (at time of writing) incompletness
 * in the javaSound package, including converting bytes from a file into
 * floats for both big and little endian formats, and support for 24 bit files.
 *
 * @author Andrew Brown, Andrew Sorensen and Tim opie
 */

public class AudioFileIn {
    // the name of the file to read from.
    private String fileName;
    // the file object to read from
    private File file;
    private AudioFileFormat fileFormat;
    private AudioFormat format;
    // Is the file data little or big endian?
    private boolean bigEndian;
    // the number of channels in the file, 1 == mono, 2 = stereo etc.
    private int channels;
    // The file's sample rate as samples per second.
    private int sampleRate;
    // The number of samples in the file
    private long duration;
    // The number of bytes long each sample is. 1 = 8 bit, 2 = 16 bit etc.
    private int sampleSize;
    // Audio intput stream, will hold the byte array of sample data.
    private AudioInputStream is;
    // the float Array with the sample in it
    private float[] sampleData;
    // Is the file an audio file?
    private boolean audioFileSpecified = true;

    /**
     * This constructor opens a file and prepares it to be read.
     *
     * @param fileName The name of the file to read, e.g., filename.aif
     */
    public AudioFileIn(String fileName) {
        this.fileName = fileName;
        try {
            this.file = new File(fileName);
            this.fileFormat = AudioSystem.getAudioFileFormat(this.file);
            this.format = this.fileFormat.getFormat();
            this.bigEndian = this.format.isBigEndian();
            channels = format.getChannels();
            sampleRate = (int) format.getSampleRate();
            this.duration = (long) this.fileFormat.getFrameLength() * this.channels;
            this.sampleSize = (format.getSampleSizeInBits()) / 8;
        } catch (UnsupportedAudioFileException uafe) {
            System.err.println("jMusic AudioFileIn warning: '" + fileName
                    + "' may not be an audio file.");
            System.err.println("Reading it in as raw data...");
            this.audioFileSpecified = false;
            this.channels = 1;
            this.sampleSize = 1;
            this.sampleRate = 0;
        } catch (IOException ioe) {
            System.err.println("jMusic AudioFileIn error: Cannot read the specified file: " + fileName);
            System.err.println("Most likely the file does not exist at this location. Exiting...");
            System.exit(0);
        }
    }

    // get the sample data from the file and put it into a float arrray.
    private void readFile() {
        if (audioFileSpecified) {
            try {
                this.is = AudioSystem.getAudioInputStream(this.file);
                byte[] tmp = new byte[(int) this.duration * this.sampleSize];
                this.is.read(tmp);
                this.is.close();
                ByteArrayInputStream bis = new ByteArrayInputStream(tmp);
                // convert to floats
                this.sampleData = new float[(int) this.duration];
                byte[] sampleWord = new byte[sampleSize];
                for (int i = 0; i < this.duration; i++) {
                    if (bis.read(sampleWord) == -1) {
                        //this.finished = true;
                        System.out.println("Ran out of samples to read");
                    } else {
                        sampleData[i] = this.getFloat(sampleWord);
                    }
                }
                bis.close();
            } catch (UnsupportedAudioFileException uafe) {
                //??
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        } else { // read any file as raw byte=sample data
            Vector buffer = new Vector();
            try {
                FileInputStream fis = new FileInputStream(this.fileName);
                int val = fis.read();
                while (val != -1) {
                    buffer.addElement(new Float((float) val / 255f));
                    val = fis.read();
                }
                fis.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
                System.exit(1);
            }
            // convert to float array
            int max = buffer.size();
            this.sampleData = new float[max];
            for (int i = 0; i < max; i++) {
                sampleData[i] = (((Float) buffer.elementAt(i)).floatValue());
            }
        }
    }

    /**
     * Provide the bit size of the current audio file.
     *
     * @return The bit depth, 8, 16, 24, or 32.
     */
    public int getBitResolution() {
        int depth = -1;
        switch (this.sampleSize) {
            case 1:
                depth = 8;
                break;
            case 2:
                depth = 16;
                break;
            case 3:
                depth = 24;
                break;
            case 4:
                depth = 32;
                break;
        }
        return depth;
    }

    /**
     * BigEndian conversion
     */
    private float getFloat(byte[] b) {
        float sample = 0.0f;
        int ret = 0;
        int length = b.length;
        for (int i = 0; i < b.length; i++, length--) {
            ret |= ((int) (b[i] & 0xFF) << ((((bigEndian) ? length : (i + 1)) * 8) - 8));
        }
        switch (sampleSize) {
            case 1:
                if (ret > 0x7F) {
                    ret = ~ret;
                    ret &= 0x7F;
                    ret = ~ret + 1;
                }
                sample = (float) ((float) ret / (float) Byte.MAX_VALUE);
                break;
            case 2:
                if (ret > 0x7FFF) {
                    ret = ~ret;
                    ret &= 0x7FFF;
                    ret = ~ret + 1;
                }
                sample = (float) ((float) ret / (float) Short.MAX_VALUE);
                break;
            case 3:
                if (ret > 0x7FFFFF) {
                    ret = ~ret;
                    ret &= 0x7FFFFF;
                    ret = ~ret + 1;
                }
                sample = (float) ((float) ret / 8388608f);
                break;
            case 4:
                sample = (float) ((double) ret / (double) Integer.MAX_VALUE);
                break;
            default:
                System.err.println("Format not accepted");
        }
        return sample;
    }

    /**
     * Provides a single array with the raw sample data in the format of the
     * source file. Check the number of channels and file type if required.
     *
     * @return sampleData the audio data as an array of floating point values.
     */
    public float[] getSampleData() {
        readFile();
        return this.sampleData;
    }

    /**
     * Supplies the number of channels in the audio file/data.
     *
     * @return channels The number of audio channels, 1 = mono, 2 = stereo etc.
     */
    public int getChannels() {
        return this.channels;
    }

    /**
     * Return the type of file, wav, aif, au etc.
     *
     * @return fileType The type of file as a string.
     */
    public String getFileType() {
        if (audioFileSpecified)
            return fileFormat.toString();
        else return new String("Non-audio");
    }

    /**
     * Access the sample rate.
     *
     * @return sampleRate The number of samples per second.
     */
    public int getSampleRate() {
        return this.sampleRate;
    }


    /**
     * Access the sample size as a number of bits per sample.
     *
     * @return bitDepth The number of bits per sample, 8, 16, 24, 32 etc.
     */
    public int getSampleBitDepth() {
        return this.sampleSize * 8;
    }

    /**
     * Indicates the type of encoding used by the file.
     *
     * @return encodingInfo A string containing the encoding type.
     */
    public String getEncoding() {
        return this.format.getEncoding().toString();
    }

    /**
     * Access the number of samples in the file.
     *
     * @return duration - The total number of samples.
     */
    public int getDuration() {
        return (int) this.duration;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy