/*
 * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.media.sound;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.AudioFileFormat.Type;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;

AIFF file reader and writer.
Author:Kara Kytle, Jan Borgersen, Florian Bomers
/** * AIFF file reader and writer. * * @author Kara Kytle * @author Jan Borgersen * @author Florian Bomers */
public final class AiffFileReader extends SunFileReader { @Override StandardFileFormat getAudioFileFormatImpl(final InputStream stream) throws UnsupportedAudioFileException, IOException { DataInputStream dis = new DataInputStream(stream); AudioFormat format = null; // Read the magic number int magic = dis.readInt(); // $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037 if (magic != AiffFileFormat.AIFF_MAGIC) { // not AIFF, throw exception throw new UnsupportedAudioFileException("not an AIFF file"); } long /* unsigned 32bit */ frameLength = 0; int length = dis.readInt(); int iffType = dis.readInt(); final long totallength; if(length <= 0 ) { length = AudioSystem.NOT_SPECIFIED; totallength = AudioSystem.NOT_SPECIFIED; } else { totallength = length + 8; } // Is this an AIFC or just plain AIFF file. boolean aifc = false; // $$fb: fix for 4369044: javax.sound.sampled.AudioSystem.getAudioInputStream() works wrong with Cp037 if (iffType == AiffFileFormat.AIFC_MAGIC) { aifc = true; } // Loop through the AIFF chunks until // we get to the SSND chunk. boolean ssndFound = false; while (!ssndFound) { // Read the chunk name int chunkName = dis.readInt(); int chunkLen = dis.readInt(); int chunkRead = 0; // Switch on the chunk name. switch (chunkName) { case AiffFileFormat.FVER_MAGIC: // Ignore format version for now. break; case AiffFileFormat.COMM_MAGIC: // AIFF vs. AIFC // $$fb: fix for 4399551: Repost of bug candidate: cannot replay aif file (Review ID: 108108) if ((!aifc && chunkLen < 18) || (aifc && chunkLen < 22)) { throw new UnsupportedAudioFileException("Invalid AIFF/COMM chunksize"); } // Read header info. int channels = dis.readUnsignedShort(); if (channels <= 0) { throw new UnsupportedAudioFileException("Invalid number of channels"); } frameLength = dis.readInt() & 0xffffffffL; // numSampleFrames int sampleSizeInBits = dis.readUnsignedShort(); if (sampleSizeInBits < 1 || sampleSizeInBits > 32) { throw new UnsupportedAudioFileException("Invalid AIFF/COMM sampleSize"); } float sampleRate = (float) read_ieee_extended(dis); chunkRead += (2 + 4 + 2 + 10); // If this is not AIFC then we assume it's // a linearly encoded file. AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED; if (aifc) { int enc = dis.readInt(); chunkRead += 4; switch (enc) { case AiffFileFormat.AIFC_PCM: encoding = AudioFormat.Encoding.PCM_SIGNED; break; case AiffFileFormat.AIFC_ULAW: encoding = AudioFormat.Encoding.ULAW; sampleSizeInBits = 8; // Java Sound convention break; default: throw new UnsupportedAudioFileException("Invalid AIFF encoding"); } } int frameSize = calculatePCMFrameSize(sampleSizeInBits, channels); //$fb what's that ?? //if (sampleSizeInBits == 8) { // encoding = AudioFormat.Encoding.PCM_SIGNED; //} format = new AudioFormat(encoding, sampleRate, sampleSizeInBits, channels, frameSize, sampleRate, true); break; case AiffFileFormat.SSND_MAGIC: // Data chunk. int dataOffset = dis.readInt(); // for now unused in javasound int blocksize = dis.readInt(); // for now unused in javasound chunkRead += 8; ssndFound = true; break; } // switch // skip the remainder of this chunk if (!ssndFound) { int toSkip = chunkLen - chunkRead; if (toSkip > 0) { dis.skipBytes(toSkip); } } } // while if (format == null) { throw new UnsupportedAudioFileException("missing COMM chunk"); } Type type = aifc ? Type.AIFC : Type.AIFF; return new AiffFileFormat(type, totallength, format, frameLength); } // HELPER METHODS
read_ieee_extended Extended precision IEEE floating-point conversion routine.
Throws:
@argumentDataInputStream
Returns:double
/** * read_ieee_extended * Extended precision IEEE floating-point conversion routine. * @argument DataInputStream * @return double * @exception IOException */
private double read_ieee_extended(DataInputStream dis) throws IOException { double f = 0; int expon = 0; long hiMant = 0, loMant = 0; long t1, t2; double HUGE = 3.40282346638528860e+38; expon = dis.readUnsignedShort(); t1 = (long)dis.readUnsignedShort(); t2 = (long)dis.readUnsignedShort(); hiMant = t1 << 16 | t2; t1 = (long)dis.readUnsignedShort(); t2 = (long)dis.readUnsignedShort(); loMant = t1 << 16 | t2; if (expon == 0 && hiMant == 0 && loMant == 0) { f = 0; } else { if (expon == 0x7FFF) f = HUGE; else { expon -= 16383; expon -= 31; f = (hiMant * Math.pow(2, expon)); expon -= 32; f += (loMant * Math.pow(2, expon)); } } return f; } }